build.sh: - Changed injection from ServerConsoleContainer to AfterInformation.tsx - Card now appears in right column after Network stats wrapper.tsx: - Redesigned to match Pterodactyl StatBlock aesthetic - Uses Tailwind classes (bg-gray-600, rounded, etc.) - FontAwesome cube icon with status colors - Compact layout: title + Check button on one line - Fire (#FF6B35/orange-400) for updates, Frost (#4ECDC4/cyan-400) for current Fixes layout issue identified in Wizard review. Signed-off-by: Claude (Chronicler #63) <claude@firefrostgaming.com>
112 lines
4.3 KiB
TypeScript
112 lines
4.3 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { ServerContext } from '@/state/server';
|
|
import http from '@/api/http';
|
|
import { faCube } from '@fortawesome/free-solid-svg-icons';
|
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
|
|
|
interface VersionData {
|
|
success: boolean;
|
|
platform?: string;
|
|
modpack_id?: string;
|
|
modpack_name?: string;
|
|
current_version?: string;
|
|
latest_version?: string;
|
|
status?: string;
|
|
message?: string;
|
|
error?: string;
|
|
}
|
|
|
|
const ModpackVersionCard: React.FC = () => {
|
|
const uuid = ServerContext.useStoreState((state) => state.server.data?.uuid);
|
|
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
|
|
const [data, setData] = useState<VersionData | null>(null);
|
|
|
|
const checkForUpdates = async () => {
|
|
if (!uuid) return;
|
|
|
|
setStatus('loading');
|
|
try {
|
|
const response = await http.post(`/api/client/extensions/modpackchecker/servers/${uuid}/check`);
|
|
setData(response.data);
|
|
setStatus(response.data.success ? 'success' : 'error');
|
|
} catch (error: any) {
|
|
if (error.response?.status === 429) {
|
|
setData({
|
|
success: false,
|
|
error: 'Rate limit reached. Please wait 60 seconds.',
|
|
});
|
|
} else {
|
|
setData({
|
|
success: false,
|
|
error: error.response?.data?.message || 'Failed to check for updates',
|
|
});
|
|
}
|
|
setStatus('error');
|
|
}
|
|
};
|
|
|
|
// Match StatBlock styling from Pterodactyl
|
|
return (
|
|
<div className={'bg-gray-600 rounded p-3 mt-2'}>
|
|
<div className={'flex items-center justify-between'}>
|
|
<div className={'flex items-center'}>
|
|
<FontAwesomeIcon
|
|
icon={faCube}
|
|
className={`w-4 h-4 mr-2 ${
|
|
status === 'success' && data?.status === 'update_available'
|
|
? 'text-orange-400'
|
|
: status === 'success'
|
|
? 'text-cyan-400'
|
|
: 'text-gray-400'
|
|
}`}
|
|
/>
|
|
<span className={'text-gray-200 text-sm font-medium'}>Modpack</span>
|
|
</div>
|
|
{status === 'idle' && (
|
|
<button
|
|
onClick={checkForUpdates}
|
|
className={'text-xs text-cyan-400 hover:text-cyan-300 transition-colors'}
|
|
>
|
|
Check
|
|
</button>
|
|
)}
|
|
{status === 'success' && (
|
|
<button
|
|
onClick={checkForUpdates}
|
|
className={'text-xs text-gray-400 hover:text-gray-300 transition-colors'}
|
|
>
|
|
Refresh
|
|
</button>
|
|
)}
|
|
</div>
|
|
<div className={'mt-1'}>
|
|
{status === 'idle' && (
|
|
<span className={'text-gray-400 text-sm'}>Click to check</span>
|
|
)}
|
|
{status === 'loading' && (
|
|
<span className={'text-gray-400 text-sm'}>Checking...</span>
|
|
)}
|
|
{status === 'success' && data?.success && (
|
|
<div>
|
|
<span className={'text-white text-sm font-semibold'}>
|
|
{data.modpack_name || data.modpack_id}
|
|
</span>
|
|
<span className={`ml-2 text-xs ${
|
|
data.status === 'update_available' ? 'text-orange-400' : 'text-cyan-400'
|
|
}`}>
|
|
{data.status === 'update_available' ? `→ ${data.latest_version}` : 'Up to date'}
|
|
</span>
|
|
</div>
|
|
)}
|
|
{(status === 'error' || (status === 'success' && !data?.success)) && (
|
|
<span className={'text-red-400 text-xs'}>
|
|
{data?.error || data?.message || 'Error'}
|
|
</span>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default ModpackVersionCard;
|