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+ // This is the correct way to use apiClient.put
99+ // It should just take the URL and the data object
100+ const response = await apiClient . put ( `/api/merchants/${ id } ` , formData ) ;
101+
102+ if ( ! response . ok ) {
103+ throw new Error ( "Failed to update merchant" ) ;
104+ }
105+
106+ toast . success ( "Merchant updated successfully" ) ;
107+ fetchMerchant ( ) ; // Refresh data
108+ } catch ( error ) {
109+ console . error ( "Error updating merchant:" , error ) ;
110+ toast . error ( "Failed to update merchant" ) ;
111+ }
112+ } ;
113+
114+ const handleDelete = async ( ) => {
115+ if ( ! confirm ( "Are you sure you want to delete this merchant?" ) ) {
116+ return ;
117+ }
118+
119+ try {
120+ const response = await apiClient . delete ( `/api/merchants/${ id } ` ) ;
121+
122+ if ( ! response . ok ) {
123+ const data = await response . json ( ) ;
124+ throw new Error ( data . error || "Failed to delete merchant" ) ;
125+ }
126+
127+ toast . success ( "Merchant deleted successfully" ) ;
128+ router . push ( "/admin/merchant" ) ;
129+ } catch ( error ) {
130+ console . error ( "Error deleting merchant:" , error ) ;
131+ toast . error (
132+ typeof error === "object" && error !== null && "message" in error
133+ ? ( error as { message ?: string } ) . message || "Failed to delete merchant"
134+ : "Failed to delete merchant"
135+ ) ;
136+ }
137+ } ;
138+
139+ if ( loading ) {
140+ return (
141+ < div className = "flex h-screen" >
142+ < DashboardSidebar />
143+ < div className = "flex-1 p-10 flex items-center justify-center" >
144+ Loading merchant details...
145+ </ div >
146+ </ div >
147+ ) ;
148+ }
149+
150+ if ( ! merchant ) {
151+ return (
152+ < div className = "flex h-screen" >
153+ < DashboardSidebar />
154+ < div className = "flex-1 p-10 flex items-center justify-center" >
155+ Merchant not found
156+ </ div >
157+ </ div >
158+ ) ;
159+ }
160+
161+ return (
162+ < div className = "flex h-screen" >
163+ < DashboardSidebar />
164+ < div className = "flex-1 p-10 overflow-y-auto" >
165+ < div className = "flex justify-between items-center mb-6" >
166+ < h1 className = "text-3xl font-bold" > Merchant Details</ h1 >
167+ < div className = "flex gap-4" >
168+ < Link
169+ href = "/admin/merchant"
170+ className = "bg-gray-500 text-white px-6 py-2 rounded-md hover:bg-gray-600 transition"
171+ >
172+ Back to Merchants
173+ </ Link >
174+ < button
175+ onClick = { handleDelete }
176+ className = "bg-red-500 text-white px-6 py-2 rounded-md hover:bg-red-600 transition"
177+ >
178+ Delete Merchant
179+ </ button >
180+ </ div >
181+ </ div >
182+
183+ < div className = "bg-white rounded-lg shadow-md p-6 mb-6" >
184+ < form onSubmit = { handleSubmit } className = "grid grid-cols-1 md:grid-cols-2 gap-6" >
185+ < div >
186+ < label className = "block text-gray-700 font-medium mb-2" > Name</ label >
187+ < input
188+ type = "text"
189+ name = "name"
190+ value = { formData . name }
191+ onChange = { handleInputChange }
192+ className = "w-full p-2 border rounded focus:outline-none focus:ring focus:border-blue-300"
193+ required
194+ />
195+ </ div >
196+ < div >
197+ < label className = "block text-gray-700 font-medium mb-2" > Email</ label >
198+ < input
199+ type = "email"
200+ name = "email"
201+ value = { formData . email }
202+ onChange = { handleInputChange }
203+ className = "w-full p-2 border rounded focus:outline-none focus:ring focus:border-blue-300"
204+ />
205+ </ div >
206+ < div >
207+ < label className = "block text-gray-700 font-medium mb-2" > Phone</ label >
208+ < input
209+ type = "text"
210+ name = "phone"
211+ value = { formData . phone }
212+ onChange = { handleInputChange }
213+ className = "w-full p-2 border rounded focus:outline-none focus:ring focus:border-blue-300"
214+ />
215+ </ div >
216+ < div >
217+ < label className = "block text-gray-700 font-medium mb-2" > Status</ label >
218+ < select
219+ name = "status"
220+ value = { formData . status }
221+ onChange = { handleInputChange }
222+ className = "w-full p-2 border rounded focus:outline-none focus:ring focus:border-blue-300"
223+ >
224+ < option value = "ACTIVE" > Active</ option >
225+ < option value = "INACTIVE" > Inactive</ option >
226+ </ select >
227+ </ div >
228+ < div className = "md:col-span-2" >
229+ < label className = "block text-gray-700 font-medium mb-2" > Address</ label >
230+ < input
231+ type = "text"
232+ name = "address"
233+ value = { formData . address }
234+ onChange = { handleInputChange }
235+ className = "w-full p-2 border rounded focus:outline-none focus:ring focus:border-blue-300"
236+ />
237+ </ div >
238+ < div className = "md:col-span-2" >
239+ < label className = "block text-gray-700 font-medium mb-2" > Description</ label >
240+ < textarea
241+ name = "description"
242+ value = { formData . description }
243+ onChange = { handleInputChange }
244+ className = "w-full p-2 border rounded focus:outline-none focus:ring focus:border-blue-300 h-32"
245+ > </ textarea >
246+ </ div >
247+ < div className = "md:col-span-2" >
248+ < button
249+ type = "submit"
250+ className = "bg-blue-500 text-white px-6 py-2 rounded-md hover:bg-blue-600 transition"
251+ >
252+ Save Changes
253+ </ button >
254+ </ div >
255+ </ form >
256+ </ div >
257+
258+ < div className = "bg-white rounded-lg shadow-md p-6" >
259+ < h2 className = "text-xl font-bold mb-4" > Merchant Products</ h2 >
260+ { merchant . products . length > 0 ? (
261+ < table className = "w-full" >
262+ < thead >
263+ < tr className = "border-b" >
264+ < th className = "py-3 text-left" > Title</ th >
265+ < th className = "py-3 text-left" > Price</ th >
266+ < th className = "py-3 text-left" > In Stock</ th >
267+ < th className = "py-3 text-left" > Actions</ th >
268+ </ tr >
269+ </ thead >
270+ < tbody >
271+ { merchant . products . map ( ( product ) => (
272+ < tr key = { product . id } className = "border-b hover:bg-gray-50" >
273+ < td className = "py-4" > { product . title } </ td >
274+ < td className = "py-4" > ${ product . price / 100 } </ td >
275+ < td className = "py-4" > { product . inStock } </ td >
276+ < td className = "py-4" >
277+ < Link
278+ href = { `/admin/products/${ product . id } ` }
279+ className = "text-blue-500 hover:underline"
280+ >
281+ View
282+ </ Link >
283+ </ td >
284+ </ tr >
285+ ) ) }
286+ </ tbody >
287+ </ table >
288+ ) : (
289+ < p className = "text-gray-500" > No products for this merchant yet.</ p >
290+ ) }
291+ </ div >
292+ </ div >
293+ </ div >
294+ ) ;
295+ }
0 commit comments