From adf653e5e17cbf0dcb7ac06b3aac4118e5f7ca73 Mon Sep 17 00:00:00 2001 From: tema Date: Tue, 9 Sep 2025 18:50:31 +0900 Subject: [PATCH] Enhance eSIM reissue functionality with optional EID transfer - Updated SimManagementService to allow reissuing eSIM profiles with an optional new EID, including validation for the EID format. - Modified SubscriptionsController to accept a new EID in the request body for the eSIM reissue endpoint. - Implemented a new React component for the eSIM reissue page, featuring form validation and user feedback for successful or failed requests. --- .../subscriptions/sim-management.service.ts | 17 ++- .../subscriptions/subscriptions.controller.ts | 17 ++- .../subscriptions/[id]/sim/reissue/page.tsx | 119 +++++++++++++++++- 3 files changed, 146 insertions(+), 7 deletions(-) diff --git a/apps/bff/src/subscriptions/sim-management.service.ts b/apps/bff/src/subscriptions/sim-management.service.ts index 9628c673..31f1f8f3 100644 --- a/apps/bff/src/subscriptions/sim-management.service.ts +++ b/apps/bff/src/subscriptions/sim-management.service.ts @@ -751,7 +751,7 @@ export class SimManagementService { /** * Reissue eSIM profile */ - async reissueEsimProfile(userId: string, subscriptionId: number): Promise { + async reissueEsimProfile(userId: string, subscriptionId: number, newEid?: string): Promise { try { const { account } = await this.validateSimSubscription(userId, subscriptionId); @@ -761,18 +761,31 @@ export class SimManagementService { throw new BadRequestException("This operation is only available for eSIM subscriptions"); } - await this.freebititService.reissueEsimProfile(account); + if (newEid) { + if (!/^\d{32}$/.test(newEid)) { + throw new BadRequestException('Invalid EID format. Expected 32 digits.'); + } + await this.freebititService.reissueEsimProfileEnhanced(account, newEid, { + oldEid: simDetails.eid, + planCode: simDetails.planCode, + }); + } else { + await this.freebititService.reissueEsimProfile(account); + } this.logger.log(`Successfully reissued eSIM profile for subscription ${subscriptionId}`, { userId, subscriptionId, account, + oldEid: simDetails.eid, + newEid: newEid || undefined, }); } catch (error) { this.logger.error(`Failed to reissue eSIM profile for subscription ${subscriptionId}`, { error: getErrorMessage(error), userId, subscriptionId, + newEid: newEid || undefined, }); throw error; } diff --git a/apps/bff/src/subscriptions/subscriptions.controller.ts b/apps/bff/src/subscriptions/subscriptions.controller.ts index c1ae7346..2b53945e 100644 --- a/apps/bff/src/subscriptions/subscriptions.controller.ts +++ b/apps/bff/src/subscriptions/subscriptions.controller.ts @@ -373,16 +373,27 @@ export class SubscriptionsController { @Post(":id/sim/reissue-esim") @ApiOperation({ summary: "Reissue eSIM profile", - description: "Reissue a downloadable eSIM profile (eSIM only)", + description: "Reissue a downloadable eSIM profile (eSIM only). Optionally provide a new EID to transfer to.", }) @ApiParam({ name: "id", type: Number, description: "Subscription ID" }) + @ApiBody({ + description: "Optional new EID to transfer the eSIM to", + schema: { + type: "object", + properties: { + newEid: { type: "string", description: "32-digit EID", example: "89049032000001000000043598005455" }, + }, + required: [], + }, + }) @ApiResponse({ status: 200, description: "eSIM reissue successful" }) @ApiResponse({ status: 400, description: "Not an eSIM subscription" }) async reissueEsimProfile( @Request() req: RequestWithUser, - @Param("id", ParseIntPipe) subscriptionId: number + @Param("id", ParseIntPipe) subscriptionId: number, + @Body() body: { newEid?: string } = {} ) { - await this.simManagementService.reissueEsimProfile(req.user.id, subscriptionId); + await this.simManagementService.reissueEsimProfile(req.user.id, subscriptionId, body.newEid); return { success: true, message: "eSIM profile reissue completed successfully" }; } diff --git a/apps/portal/src/app/subscriptions/[id]/sim/reissue/page.tsx b/apps/portal/src/app/subscriptions/[id]/sim/reissue/page.tsx index 67e08591..37a8de64 100644 --- a/apps/portal/src/app/subscriptions/[id]/sim/reissue/page.tsx +++ b/apps/portal/src/app/subscriptions/[id]/sim/reissue/page.tsx @@ -1,3 +1,118 @@ -export default function Page() { - return null; +"use client"; + +import { useEffect, useState } from "react"; +import Link from "next/link"; +import { useParams, useRouter } from "next/navigation"; +import { DashboardLayout } from "@/components/layout/dashboard-layout"; +import { authenticatedApi } from "@/lib/api"; + +export default function EsimReissuePage() { + const params = useParams(); + const router = useRouter(); + const subscriptionId = parseInt(params.id as string); + const [loading, setLoading] = useState(false); + const [detailsLoading, setDetailsLoading] = useState(true); + const [error, setError] = useState(null); + const [message, setMessage] = useState(null); + const [oldEid, setOldEid] = useState(null); + const [newEid, setNewEid] = useState(""); + + useEffect(() => { + const fetchDetails = async () => { + try { + setDetailsLoading(true); + const data = await authenticatedApi.get<{ eid?: string }>( + `/subscriptions/${subscriptionId}/sim/details` + ); + setOldEid(data?.eid || null); + } catch (e: any) { + setError(e instanceof Error ? e.message : "Failed to load SIM details"); + } finally { + setDetailsLoading(false); + } + }; + void fetchDetails(); + }, [subscriptionId]); + + const validEid = (val: string) => /^\d{32}$/.test(val); + + const submit = async (e: React.FormEvent) => { + e.preventDefault(); + setError(null); + setMessage(null); + if (!validEid(newEid)) { + setError("Please enter a valid 32-digit EID"); + return; + } + setLoading(true); + try { + await authenticatedApi.post(`/subscriptions/${subscriptionId}/sim/reissue-esim`, { newEid }); + setMessage("eSIM reissue requested successfully. You will receive the new profile shortly."); + setTimeout(() => router.push(`/subscriptions/${subscriptionId}#sim-management`), 1500); + } catch (e: any) { + setError(e instanceof Error ? e.message : "Failed to submit eSIM reissue"); + } finally { + setLoading(false); + } + }; + + return ( + +
+
+ ← Back to SIM Management +
+
+

Reissue eSIM

+

Enter the new EID to transfer this eSIM to. We will show your current EID for confirmation.

+ + {detailsLoading ? ( +
Loading current eSIM details…
+ ) : ( +
+ +
+ {oldEid || "—"} +
+
+ )} + + {message && ( +
{message}
+ )} + {error && ( +
{error}
+ )} + +
void submit(e)} className="space-y-4"> +
+ + setNewEid(e.target.value.trim())} + placeholder="32-digit EID (e.g., 8904….)" + className="mt-1 w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 font-mono" + maxLength={32} + /> +

Must be exactly 32 digits.

+
+
+ + + Cancel + +
+
+
+
+
+ ); }