1+ "use client" ;
2+ import React , { useEffect , useState , use } from "react" ;
3+ import DashboardSidebar from "@/components/DashboardSidebar" ;
4+ import Link from "next/link" ;
5+ import { useRouter } from "next/navigation" ;
6+ import apiClient from "@/lib/api" ;
7+ import { toast } from "react-hot-toast" ;
8+
9+ interface Product {
10+ id : string ;
11+ title : string ;
12+ price : number ;
13+ inStock : number ;
14+ }
15+
16+ interface Merchant {
17+ id : string ;
18+ name : string ;
19+ email : string | null ;
20+ phone : string | null ;
21+ address : string | null ;
22+ description : string | null ;
23+ status : string ;
24+ products : Product [ ] ;
25+ }
26+
27+ interface MerchantDetailPageProps {
28+ params : Promise < { id : string } > ;
29+ }
30+
31+ export default function MerchantDetailPage ( {
32+ params,
33+ } : MerchantDetailPageProps ) {
34+ // Unwrap params using React.use()
35+ const resolvedParams = use ( params ) ;
36+ const id = resolvedParams . id ;
37+
38+ const [ merchant , setMerchant ] = useState < Merchant | null > ( null ) ;
39+ const [ loading , setLoading ] = useState ( true ) ;
40+ const [ formData , setFormData ] = useState ( {
41+ name : "" ,
42+ email : "" ,
43+ phone : "" ,
44+ address : "" ,
45+ description : "" ,
46+ status : "ACTIVE" ,
47+ } ) ;
48+
49+ const router = useRouter ( ) ;
50+
51+ const fetchMerchant = async ( ) => {
52+ try {
53+ setLoading ( true ) ;
54+ const response = await apiClient . get ( `/api/merchants/${ id } ` ) ;
55+
56+ if ( ! response . ok ) {
57+ if ( response . status === 404 ) {
58+ router . push ( "/admin/merchant" ) ;
59+ return ;
60+ }
61+ throw new Error ( "Failed to fetch merchant" ) ;
62+ }
63+
64+ const data = await response . json ( ) ;
65+ setMerchant ( data ) ;
66+ setFormData ( {
67+ name : data . name || "" ,
68+ email : data . email || "" ,
69+ phone : data . phone || "" ,
70+ address : data . address || "" ,
71+ description : data . description || "" ,
72+ status : data . status || "ACTIVE" ,
73+ } ) ;
74+ } catch ( error ) {
75+ console . error ( "Error fetching merchant:" , error ) ;
76+ toast . error ( "Failed to load merchant details" ) ;
77+ } finally {
78+ setLoading ( false ) ;
79+ }
80+ } ;
81+
82+ useEffect ( ( ) => {
83+ fetchMerchant ( ) ;
84+ } , [ id ] ) ;
85+
86+ const handleInputChange = (
87+ e : React . ChangeEvent <
88+ HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement
89+ >
90+ ) => {
91+ const { name, value } = e . target ;
92+ setFormData ( ( prev ) => ( { ...prev , [ name ] : value } ) ) ;
93+ } ;
94+
95+ const handleSubmit = async ( e : React . FormEvent ) => {
96+ e . preventDefault ( ) ;
97+ try {
98+ const response = await apiClient . put ( `/api/merchants/${ id } ` , {
99+ method : "PUT" ,
100+ headers : { "Content-Type" : "application/json" } ,
101+ body : JSON . stringify ( formData ) ,
102+ } ) ;
103+
104+ if ( ! response . ok ) {
105+ throw new Error ( "Failed to update merchant" ) ;
106+ }
107+
108+ toast . success ( "Merchant updated successfully" ) ;
109+ fetchMerchant ( ) ; // Refresh data
110+ } catch ( error ) {
111+ console . error ( "Error updating merchant:" , error ) ;
112+ toast . error ( "Failed to update merchant" ) ;
113+ }
114+ } ;
115+
116+ const handleDelete = async ( ) => {
117+ if ( ! confirm ( "Are you sure you want to delete this merchant?" ) ) {
118+ return ;
119+ }
120+
121+ try {
122+ const response = await apiClient . delete ( `/api/merchants/${ id } ` ) ;
123+
124+ if ( ! response . ok ) {
125+ const data = await response . json ( ) ;
126+ throw new Error ( data . error || "Failed to delete merchant" ) ;
127+ }
128+
129+ toast . success ( "Merchant deleted successfully" ) ;
130+ router . push ( "/admin/merchant" ) ;
131+ } catch ( error ) {
132+ console . error ( "Error deleting merchant:" , error ) ;
133+ toast . error (
134+ typeof error === "object" && error !== null && "message" in error
135+ ? ( error as { message ?: string } ) . message || "Failed to delete merchant"
136+ : "Failed to delete merchant"
137+ ) ;
138+ }
139+ } ;
140+
141+ if ( loading ) {
142+ return (
143+ < div className = "flex h-screen" >
144+ < DashboardSidebar />
145+ < div className = "flex-1 p-10 flex items-center justify-center" >
146+ Loading merchant details...
147+ </ div >
148+ </ div >
149+ ) ;
150+ }
151+
152+ if ( ! merchant ) {
153+ return (
154+ < div className = "flex h-screen" >
155+ < DashboardSidebar />
156+ < div className = "flex-1 p-10 flex items-center justify-center" >
157+ Merchant not found
158+ </ div >
159+ </ div >
160+ ) ;
161+ }
162+
163+ return (
164+ < div className = "flex h-screen" >
165+ < DashboardSidebar />
166+ < div className = "flex-1 p-10 overflow-y-auto" >
167+ < div className = "flex justify-between items-center mb-6" >
168+ < h1 className = "text-3xl font-bold" > Merchant Details</ h1 >
169+ < div className = "flex gap-4" >
170+ < Link
171+ href = "/admin/merchant"
172+ className = "bg-gray-500 text-white px-6 py-2 rounded-md hover:bg-gray-600 transition"
173+ >
174+ Back to Merchants
175+ </ Link >
176+ < button
177+ onClick = { handleDelete }
178+ className = "bg-red-500 text-white px-6 py-2 rounded-md hover:bg-red-600 transition"
179+ >
180+ Delete Merchant
181+ </ button >
182+ </ div >
183+ </ div >
184+
185+ < div className = "bg-white rounded-lg shadow-md p-6 mb-6" >
186+ < form onSubmit = { handleSubmit } className = "grid grid-cols-1 md:grid-cols-2 gap-6" >
187+ < div >
188+ < label className = "block text-gray-700 font-medium mb-2" > Name</ label >
189+ < input
190+ type = "text"
191+ name = "name"
192+ value = { formData . name }
193+ onChange = { handleInputChange }
194+ className = "w-full p-2 border rounded focus:outline-none focus:ring focus:border-blue-300"
195+ required
196+ />
197+ </ div >
198+ < div >
199+ < label className = "block text-gray-700 font-medium mb-2" > Email</ label >
200+ < input
201+ type = "email"
202+ name = "email"
203+ value = { formData . email }
204+ onChange = { handleInputChange }
205+ className = "w-full p-2 border rounded focus:outline-none focus:ring focus:border-blue-300"
206+ />
207+ </ div >
208+ < div >
209+ < label className = "block text-gray-700 font-medium mb-2" > Phone</ label >
210+ < input
211+ type = "text"
212+ name = "phone"
213+ value = { formData . phone }
214+ onChange = { handleInputChange }
215+ className = "w-full p-2 border rounded focus:outline-none focus:ring focus:border-blue-300"
216+ />
217+ </ div >
218+ < div >
219+ < label className = "block text-gray-700 font-medium mb-2" > Status</ label >
220+ < select
221+ name = "status"
222+ value = { formData . status }
223+ onChange = { handleInputChange }
224+ className = "w-full p-2 border rounded focus:outline-none focus:ring focus:border-blue-300"
225+ >
226+ < option value = "ACTIVE" > Active</ option >
227+ < option value = "INACTIVE" > Inactive</ option >
228+ </ select >
229+ </ div >
230+ < div className = "md:col-span-2" >
231+ < label className = "block text-gray-700 font-medium mb-2" > Address</ label >
232+ < input
233+ type = "text"
234+ name = "address"
235+ value = { formData . address }
236+ onChange = { handleInputChange }
237+ className = "w-full p-2 border rounded focus:outline-none focus:ring focus:border-blue-300"
238+ />
239+ </ div >
240+ < div className = "md:col-span-2" >
241+ < label className = "block text-gray-700 font-medium mb-2" > Description</ label >
242+ < textarea
243+ name = "description"
244+ value = { formData . description }
245+ onChange = { handleInputChange }
246+ className = "w-full p-2 border rounded focus:outline-none focus:ring focus:border-blue-300 h-32"
247+ > </ textarea >
248+ </ div >
249+ < div className = "md:col-span-2" >
250+ < button
251+ type = "submit"
252+ className = "bg-blue-500 text-white px-6 py-2 rounded-md hover:bg-blue-600 transition"
253+ >
254+ Save Changes
255+ </ button >
256+ </ div >
257+ </ form >
258+ </ div >
259+
260+ < div className = "bg-white rounded-lg shadow-md p-6" >
261+ < h2 className = "text-xl font-bold mb-4" > Merchant Products</ h2 >
262+ { merchant . products . length > 0 ? (
263+ < table className = "w-full" >
264+ < thead >
265+ < tr className = "border-b" >
266+ < th className = "py-3 text-left" > Title</ th >
267+ < th className = "py-3 text-left" > Price</ th >
268+ < th className = "py-3 text-left" > In Stock</ th >
269+ < th className = "py-3 text-left" > Actions</ th >
270+ </ tr >
271+ </ thead >
272+ < tbody >
273+ { merchant . products . map ( ( product ) => (
274+ < tr key = { product . id } className = "border-b hover:bg-gray-50" >
275+ < td className = "py-4" > { product . title } </ td >
276+ < td className = "py-4" > ${ product . price / 100 } </ td >
277+ < td className = "py-4" > { product . inStock } </ td >
278+ < td className = "py-4" >
279+ < Link
280+ href = { `/admin/products/${ product . id } ` }
281+ className = "text-blue-500 hover:underline"
282+ >
283+ View
284+ </ Link >
285+ </ td >
286+ </ tr >
287+ ) ) }
288+ </ tbody >
289+ </ table >
290+ ) : (
291+ < p className = "text-gray-500" > No products for this merchant yet.</ p >
292+ ) }
293+ </ div >
294+ </ div >
295+ </ div >
296+ ) ;
297+ }
0 commit comments