Fix table responsiveness in admin pages

AdminProducts.tsx:
- Wrap table in overflow-x-auto div for horizontal scrolling
- Add whitespace-nowrap to TableHead cells
- Change form grid from grid-cols-2 to grid-cols-1 md:grid-cols-2

AdminOrders.tsx:
- Wrap table in overflow-x-auto div for horizontal scrolling
- Add whitespace-nowrap to TableHead cells
- Change detail dialog grid from grid-cols-2 to grid-cols-1 sm:grid-cols-2
- Change action buttons from flex to flex-col sm:flex-row for mobile stacking

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
dwindown
2025-12-25 08:50:17 +07:00
parent c653a174f4
commit ad95a15310
2 changed files with 90 additions and 86 deletions

View File

@@ -178,43 +178,45 @@ export default function AdminOrders() {
<Card className="border-2 border-border"> <Card className="border-2 border-border">
<CardContent className="p-0"> <CardContent className="p-0">
<Table> <div className="overflow-x-auto">
<TableHeader> <Table>
<TableRow> <TableHeader>
<TableHead>ID Order</TableHead>
<TableHead>Email</TableHead>
<TableHead>Total</TableHead>
<TableHead>Metode</TableHead>
<TableHead>Status</TableHead>
<TableHead>Tanggal</TableHead>
<TableHead className="text-right">Aksi</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{orders.map((order) => (
<TableRow key={order.id}>
<TableCell className="font-mono text-sm">{order.id.slice(0, 8)}</TableCell>
<TableCell>{order.profile?.email || "-"}</TableCell>
<TableCell className="font-bold">{formatIDR(order.total_amount)}</TableCell>
<TableCell className="uppercase text-sm">{order.payment_method || "-"}</TableCell>
<TableCell>{getStatusBadge(order.payment_status)}</TableCell>
<TableCell>{formatDateTime(order.created_at)}</TableCell>
<TableCell className="text-right">
<Button variant="ghost" size="sm" onClick={() => viewOrderDetails(order)}>
<Eye className="w-4 h-4" />
</Button>
</TableCell>
</TableRow>
))}
{orders.length === 0 && (
<TableRow> <TableRow>
<TableCell colSpan={7} className="text-center py-8 text-muted-foreground"> <TableHead className="whitespace-nowrap">ID Order</TableHead>
Belum ada order <TableHead className="whitespace-nowrap">Email</TableHead>
</TableCell> <TableHead className="whitespace-nowrap">Total</TableHead>
<TableHead className="whitespace-nowrap">Metode</TableHead>
<TableHead className="whitespace-nowrap">Status</TableHead>
<TableHead className="whitespace-nowrap">Tanggal</TableHead>
<TableHead className="text-right whitespace-nowrap">Aksi</TableHead>
</TableRow> </TableRow>
)} </TableHeader>
</TableBody> <TableBody>
</Table> {orders.map((order) => (
<TableRow key={order.id}>
<TableCell className="font-mono text-sm">{order.id.slice(0, 8)}</TableCell>
<TableCell>{order.profile?.email || "-"}</TableCell>
<TableCell className="font-bold">{formatIDR(order.total_amount)}</TableCell>
<TableCell className="uppercase text-sm">{order.payment_method || "-"}</TableCell>
<TableCell>{getStatusBadge(order.payment_status)}</TableCell>
<TableCell>{formatDateTime(order.created_at)}</TableCell>
<TableCell className="text-right">
<Button variant="ghost" size="sm" onClick={() => viewOrderDetails(order)}>
<Eye className="w-4 h-4" />
</Button>
</TableCell>
</TableRow>
))}
{orders.length === 0 && (
<TableRow>
<TableCell colSpan={7} className="text-center py-8 text-muted-foreground">
Belum ada order
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
</CardContent> </CardContent>
</Card> </Card>
@@ -225,7 +227,7 @@ export default function AdminOrders() {
</DialogHeader> </DialogHeader>
{selectedOrder && ( {selectedOrder && (
<div className="space-y-4"> <div className="space-y-4">
<div className="grid grid-cols-2 gap-2 text-sm"> <div className="grid grid-cols-1 sm:grid-cols-2 gap-2 text-sm">
<div> <div>
<span className="text-muted-foreground">ID:</span> {selectedOrder.id.slice(0, 8)} <span className="text-muted-foreground">ID:</span> {selectedOrder.id.slice(0, 8)}
</div> </div>
@@ -302,7 +304,7 @@ export default function AdminOrders() {
</div> </div>
)} )}
<div className="flex gap-2 pt-4"> <div className="flex flex-col sm:flex-row gap-2 pt-4">
{selectedOrder.payment_status !== "paid" && ( {selectedOrder.payment_status !== "paid" && (
<Button onClick={() => updateOrderStatus(selectedOrder.id, "paid")} className="flex-1"> <Button onClick={() => updateOrderStatus(selectedOrder.id, "paid")} className="flex-1">
<CheckCircle className="w-4 h-4 mr-2" /> <CheckCircle className="w-4 h-4 mr-2" />

View File

@@ -164,55 +164,57 @@ export default function AdminProducts() {
<Card className="border-2 border-border"> <Card className="border-2 border-border">
<CardContent className="p-0"> <CardContent className="p-0">
<Table> <div className="overflow-x-auto">
<TableHeader> <Table>
<TableRow> <TableHeader>
<TableHead>Judul</TableHead>
<TableHead>Tipe</TableHead>
<TableHead>Harga</TableHead>
<TableHead>Status</TableHead>
<TableHead className="text-right">Aksi</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{products.map((product) => (
<TableRow key={product.id}>
<TableCell className="font-medium">{product.title}</TableCell>
<TableCell className="capitalize">{product.type}</TableCell>
<TableCell>
{product.sale_price ? (
<span>
<span className="font-bold">{formatIDR(product.sale_price)}</span>
<span className="text-muted-foreground line-through ml-2">{formatIDR(product.price)}</span>
</span>
) : (
<span className="font-bold">{formatIDR(product.price)}</span>
)}
</TableCell>
<TableCell>
<span className={product.is_active ? 'text-foreground' : 'text-muted-foreground'}>
{product.is_active ? 'Aktif' : 'Nonaktif'}
</span>
</TableCell>
<TableCell className="text-right">
<Button variant="ghost" size="sm" onClick={() => handleEdit(product)}>
<Pencil className="w-4 h-4" />
</Button>
<Button variant="ghost" size="sm" onClick={() => handleDelete(product.id)}>
<Trash2 className="w-4 h-4" />
</Button>
</TableCell>
</TableRow>
))}
{products.length === 0 && (
<TableRow> <TableRow>
<TableCell colSpan={5} className="text-center py-8 text-muted-foreground"> <TableHead className="whitespace-nowrap">Judul</TableHead>
Belum ada produk <TableHead className="whitespace-nowrap">Tipe</TableHead>
</TableCell> <TableHead className="whitespace-nowrap">Harga</TableHead>
<TableHead className="whitespace-nowrap">Status</TableHead>
<TableHead className="text-right whitespace-nowrap">Aksi</TableHead>
</TableRow> </TableRow>
)} </TableHeader>
</TableBody> <TableBody>
</Table> {products.map((product) => (
<TableRow key={product.id}>
<TableCell className="font-medium">{product.title}</TableCell>
<TableCell className="capitalize">{product.type}</TableCell>
<TableCell>
{product.sale_price ? (
<span>
<span className="font-bold">{formatIDR(product.sale_price)}</span>
<span className="text-muted-foreground line-through ml-2">{formatIDR(product.price)}</span>
</span>
) : (
<span className="font-bold">{formatIDR(product.price)}</span>
)}
</TableCell>
<TableCell>
<span className={product.is_active ? 'text-foreground' : 'text-muted-foreground'}>
{product.is_active ? 'Aktif' : 'Nonaktif'}
</span>
</TableCell>
<TableCell className="text-right">
<Button variant="ghost" size="sm" onClick={() => handleEdit(product)}>
<Pencil className="w-4 h-4" />
</Button>
<Button variant="ghost" size="sm" onClick={() => handleDelete(product.id)}>
<Trash2 className="w-4 h-4" />
</Button>
</TableCell>
</TableRow>
))}
{products.length === 0 && (
<TableRow>
<TableCell colSpan={5} className="text-center py-8 text-muted-foreground">
Belum ada produk
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
</CardContent> </CardContent>
</Card> </Card>
@@ -227,7 +229,7 @@ export default function AdminProducts() {
{editingProduct && form.type === 'bootcamp' && <TabsTrigger value="curriculum">Kurikulum</TabsTrigger>} {editingProduct && form.type === 'bootcamp' && <TabsTrigger value="curriculum">Kurikulum</TabsTrigger>}
</TabsList> </TabsList>
<TabsContent value="details" className="space-y-4 py-4"> <TabsContent value="details" className="space-y-4 py-4">
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2"> <div className="space-y-2">
<Label>Judul *</Label> <Label>Judul *</Label>
<Input value={form.title} onChange={(e) => setForm({ ...form, title: e.target.value, slug: generateSlug(e.target.value) })} className="border-2" /> <Input value={form.title} onChange={(e) => setForm({ ...form, title: e.target.value, slug: generateSlug(e.target.value) })} className="border-2" />
@@ -255,7 +257,7 @@ export default function AdminProducts() {
<Label>Konten</Label> <Label>Konten</Label>
<RichTextEditor content={form.content} onChange={(v) => setForm({ ...form, content: v })} /> <RichTextEditor content={form.content} onChange={(v) => setForm({ ...form, content: v })} />
</div> </div>
<div className="grid grid-cols-2 gap-4"> <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div className="space-y-2"> <div className="space-y-2">
<Label>Meeting Link</Label> <Label>Meeting Link</Label>
<Input value={form.meeting_link} onChange={(e) => setForm({ ...form, meeting_link: e.target.value })} placeholder="https://meet.google.com/..." className="border-2" /> <Input value={form.meeting_link} onChange={(e) => setForm({ ...form, meeting_link: e.target.value })} placeholder="https://meet.google.com/..." className="border-2" />