Refactor Freebit plan change request and improve error handling
- Updated FreebititPlanChangeRequest interface to use 'planCode' instead of 'plancode' for consistency. - Enhanced error handling in WhmcsInvoiceService to provide a default message for payment errors. - Removed unused state variables for global IP assignment and scheduling in SIM change plan components to streamline the user interface.
This commit is contained in:
parent
c9356cad65
commit
2325cf2753
@ -467,7 +467,7 @@ export class FreebititService {
|
|||||||
try {
|
try {
|
||||||
const request: Omit<FreebititPlanChangeRequest, 'authKey'> = {
|
const request: Omit<FreebititPlanChangeRequest, 'authKey'> = {
|
||||||
account,
|
account,
|
||||||
plancode: newPlanCode,
|
planCode: newPlanCode,
|
||||||
globalip: options.assignGlobalIp ? '1' : '0',
|
globalip: options.assignGlobalIp ? '1' : '0',
|
||||||
runTime: options.scheduledAt,
|
runTime: options.scheduledAt,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -164,7 +164,7 @@ export interface FreebititQuotaHistoryResponse {
|
|||||||
export interface FreebititPlanChangeRequest {
|
export interface FreebititPlanChangeRequest {
|
||||||
authKey: string;
|
authKey: string;
|
||||||
account: string;
|
account: string;
|
||||||
plancode: string;
|
planCode: string;
|
||||||
globalip?: '0' | '1'; // 0=no IP, 1=assign global IP
|
globalip?: '0' | '1'; // 0=no IP, 1=assign global IP
|
||||||
runTime?: string; // YYYYMMDD - optional, immediate if omitted
|
runTime?: string; // YYYYMMDD - optional, immediate if omitted
|
||||||
}
|
}
|
||||||
|
|||||||
@ -370,7 +370,7 @@ export class WhmcsInvoiceService {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Return user-friendly error message instead of technical API error
|
// Return user-friendly error message instead of technical API error
|
||||||
const userFriendlyError = this.getUserFriendlyPaymentError(response.message || response.error);
|
const userFriendlyError = this.getUserFriendlyPaymentError(response.message || response.error || 'Unknown payment error');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
success: false,
|
success: false,
|
||||||
|
|||||||
@ -20,8 +20,6 @@ export default function SimChangePlanPage() {
|
|||||||
const subscriptionId = parseInt(params.id as string);
|
const subscriptionId = parseInt(params.id as string);
|
||||||
const [currentPlanCode] = useState<string>("");
|
const [currentPlanCode] = useState<string>("");
|
||||||
const [newPlanCode, setNewPlanCode] = useState<"" | PlanCode>("");
|
const [newPlanCode, setNewPlanCode] = useState<"" | PlanCode>("");
|
||||||
const [assignGlobalIp, setAssignGlobalIp] = useState(false);
|
|
||||||
const [scheduledAt, setScheduledAt] = useState("");
|
|
||||||
const [message, setMessage] = useState<string | null>(null);
|
const [message, setMessage] = useState<string | null>(null);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@ -40,8 +38,6 @@ export default function SimChangePlanPage() {
|
|||||||
try {
|
try {
|
||||||
await authenticatedApi.post(`/subscriptions/${subscriptionId}/sim/change-plan`, {
|
await authenticatedApi.post(`/subscriptions/${subscriptionId}/sim/change-plan`, {
|
||||||
newPlanCode,
|
newPlanCode,
|
||||||
assignGlobalIp,
|
|
||||||
scheduledAt: scheduledAt ? scheduledAt.replace(/-/g, "") : undefined,
|
|
||||||
});
|
});
|
||||||
setMessage("Plan change submitted successfully");
|
setMessage("Plan change submitted successfully");
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
@ -78,16 +74,6 @@ export default function SimChangePlanPage() {
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex items-center">
|
|
||||||
<input id="globalip" type="checkbox" checked={assignGlobalIp} onChange={(e)=>setAssignGlobalIp(e.target.checked)} className="h-4 w-4 text-blue-600 border-gray-300 rounded" />
|
|
||||||
<label htmlFor="globalip" className="ml-2 text-sm text-gray-700">Assign global IP</label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-2">Schedule (optional)</label>
|
|
||||||
<input type="date" value={scheduledAt} onChange={(e)=>setScheduledAt(e.target.value)} className="w-full px-3 py-2 border border-gray-300 rounded-md" />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
<button type="submit" disabled={loading} className="px-4 py-2 rounded-md bg-blue-600 text-white text-sm disabled:opacity-50">{loading ? 'Processing…' : 'Submit Plan Change'}</button>
|
<button type="submit" disabled={loading} className="px-4 py-2 rounded-md bg-blue-600 text-white text-sm disabled:opacity-50">{loading ? 'Processing…' : 'Submit Plan Change'}</button>
|
||||||
<Link href={`/subscriptions/${subscriptionId}#sim-management`} className="px-4 py-2 rounded-md border border-gray-300 text-sm text-gray-700 bg-white hover:bg-gray-50">Back</Link>
|
<Link href={`/subscriptions/${subscriptionId}#sim-management`} className="px-4 py-2 rounded-md border border-gray-300 text-sm text-gray-700 bg-white hover:bg-gray-50">Back</Link>
|
||||||
|
|||||||
@ -25,8 +25,6 @@ export function ChangePlanModal({ subscriptionId, currentPlanCode, onClose, onSu
|
|||||||
const allowedPlans = (PLAN_CODES as readonly PlanCode[]).filter(code => code !== (currentPlanCode || ''));
|
const allowedPlans = (PLAN_CODES as readonly PlanCode[]).filter(code => code !== (currentPlanCode || ''));
|
||||||
|
|
||||||
const [newPlanCode, setNewPlanCode] = useState<"" | PlanCode>("");
|
const [newPlanCode, setNewPlanCode] = useState<"" | PlanCode>("");
|
||||||
const [assignGlobalIp, setAssignGlobalIp] = useState(false);
|
|
||||||
const [scheduledAt, setScheduledAt] = useState(""); // YYYY-MM-DD
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
@ -38,8 +36,6 @@ export function ChangePlanModal({ subscriptionId, currentPlanCode, onClose, onSu
|
|||||||
try {
|
try {
|
||||||
await authenticatedApi.post(`/subscriptions/${subscriptionId}/sim/change-plan`, {
|
await authenticatedApi.post(`/subscriptions/${subscriptionId}/sim/change-plan`, {
|
||||||
newPlanCode: newPlanCode,
|
newPlanCode: newPlanCode,
|
||||||
assignGlobalIp,
|
|
||||||
scheduledAt: scheduledAt ? scheduledAt.replaceAll("-", "") : undefined,
|
|
||||||
});
|
});
|
||||||
onSuccess();
|
onSuccess();
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
@ -78,29 +74,7 @@ export function ChangePlanModal({ subscriptionId, currentPlanCode, onClose, onSu
|
|||||||
<option key={code} value={code}>{PLAN_LABELS[code]}</option>
|
<option key={code} value={code}>{PLAN_LABELS[code]}</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
<p className="mt-1 text-xs text-gray-500">Only plans different from your current plan are listed.</p>
|
<p className="mt-1 text-xs text-gray-500">Only plans different from your current plan are listed. The change will be scheduled for the 1st of the next month.</p>
|
||||||
</div>
|
|
||||||
<div className="flex items-center">
|
|
||||||
<input
|
|
||||||
id="assignGlobalIp"
|
|
||||||
type="checkbox"
|
|
||||||
checked={assignGlobalIp}
|
|
||||||
onChange={(e) => setAssignGlobalIp(e.target.checked)}
|
|
||||||
className="h-4 w-4 text-blue-600 border-gray-300 rounded"
|
|
||||||
/>
|
|
||||||
<label htmlFor="assignGlobalIp" className="ml-2 block text-sm text-gray-700">
|
|
||||||
Assign global IP address
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-medium text-gray-700">Schedule Date (optional)</label>
|
|
||||||
<input
|
|
||||||
type="date"
|
|
||||||
value={scheduledAt}
|
|
||||||
onChange={(e) => setScheduledAt(e.target.value)}
|
|
||||||
className="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-blue-500 focus:ring-blue-500 text-sm"
|
|
||||||
/>
|
|
||||||
<p className="mt-1 text-xs text-gray-500">If empty, the plan change is processed immediately.</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user