Skip to content

Commit a2a34bb

Browse files
committed
feat: use ecommerce client instead of client id for naming, implement table of clients and CRUD actions
1 parent b688754 commit a2a34bb

File tree

16 files changed

+686
-356
lines changed

16 files changed

+686
-356
lines changed

src/app/ecommerce/manage/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export default async function ManagePage() {
1010
redirect("/");
1111
}
1212

13-
const clientIds = await api.clientId.getAll.query();
13+
const ecommerceClients = await api.ecommerce.getAll.query();
1414

15-
return <EcommerceManage initialClientIds={clientIds} />;
15+
return <EcommerceManage initialEcommerceClients={ecommerceClients} />;
1616
}
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
"use client";
2+
3+
import { Button } from "@/components/ui/button";
4+
import {
5+
Form,
6+
FormControl,
7+
FormField,
8+
FormItem,
9+
FormLabel,
10+
FormMessage,
11+
} from "@/components/ui/form";
12+
import { Input } from "@/components/ui/input";
13+
import { zodResolver } from "@hookform/resolvers/zod";
14+
import { Loader2 } from "lucide-react";
15+
import { useForm } from "react-hook-form";
16+
import {
17+
type EcommerceClientFormValues,
18+
ecommerceClientFormSchema,
19+
} from "./types";
20+
21+
interface EcommerceClientFormProps {
22+
onSubmit: (data: EcommerceClientFormValues) => void;
23+
isLoading?: boolean;
24+
defaultValues?: Partial<EcommerceClientFormValues>;
25+
submitButtonText?: string;
26+
onCancel?: () => void;
27+
}
28+
29+
export function EcommerceClientForm({
30+
onSubmit,
31+
isLoading = false,
32+
defaultValues,
33+
submitButtonText = "Create Client ID",
34+
onCancel,
35+
}: EcommerceClientFormProps) {
36+
const form = useForm<EcommerceClientFormValues>({
37+
resolver: zodResolver(ecommerceClientFormSchema),
38+
defaultValues: {
39+
label: "",
40+
domain: "",
41+
feeAddress: undefined,
42+
feePercentage: undefined,
43+
...defaultValues,
44+
},
45+
});
46+
47+
return (
48+
<Form {...form}>
49+
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4">
50+
<FormField
51+
control={form.control}
52+
name="label"
53+
render={({ field }) => (
54+
<FormItem>
55+
<FormLabel>Label</FormLabel>
56+
<FormControl>
57+
<Input
58+
placeholder="My Ecommerce Store"
59+
disabled={isLoading}
60+
{...field}
61+
/>
62+
</FormControl>
63+
<FormMessage />
64+
</FormItem>
65+
)}
66+
/>
67+
68+
<FormField
69+
control={form.control}
70+
name="domain"
71+
render={({ field }) => (
72+
<FormItem>
73+
<FormLabel>Domain</FormLabel>
74+
<FormControl>
75+
<Input
76+
placeholder="https://mystore.com"
77+
disabled={isLoading}
78+
{...field}
79+
/>
80+
</FormControl>
81+
<FormMessage />
82+
</FormItem>
83+
)}
84+
/>
85+
86+
<FormField
87+
control={form.control}
88+
name="feeAddress"
89+
render={({ field }) => (
90+
<FormItem>
91+
<FormLabel>Fee Address (Optional)</FormLabel>
92+
<FormControl>
93+
<Input
94+
placeholder="0x..."
95+
className="font-mono"
96+
disabled={isLoading}
97+
{...field}
98+
/>
99+
</FormControl>
100+
<FormMessage />
101+
</FormItem>
102+
)}
103+
/>
104+
105+
<FormField
106+
control={form.control}
107+
name="feePercentage"
108+
render={({ field }) => (
109+
<FormItem>
110+
<FormLabel>Fee Percentage (Optional)</FormLabel>
111+
<FormControl>
112+
<Input
113+
type="number"
114+
placeholder="5"
115+
min="0"
116+
max="100"
117+
step="0.1"
118+
disabled={isLoading}
119+
value={field.value || ""}
120+
onChange={(e) =>
121+
field.onChange(
122+
e.target.value ? Number(e.target.value) : undefined,
123+
)
124+
}
125+
/>
126+
</FormControl>
127+
<FormMessage />
128+
</FormItem>
129+
)}
130+
/>
131+
132+
<div className="flex justify-end gap-2 pt-4">
133+
{onCancel && (
134+
<Button
135+
type="button"
136+
variant="outline"
137+
onClick={onCancel}
138+
disabled={isLoading}
139+
>
140+
Cancel
141+
</Button>
142+
)}
143+
<Button type="submit" disabled={isLoading}>
144+
{isLoading ? (
145+
<>
146+
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
147+
{submitButtonText.includes("Create")
148+
? "Creating..."
149+
: "Updating..."}
150+
</>
151+
) : (
152+
submitButtonText
153+
)}
154+
</Button>
155+
</div>
156+
</form>
157+
</Form>
158+
);
159+
}

src/components/ecommerce/manage/blocks/client-ids-table.tsx renamed to src/components/ecommerce/manage/blocks/clients-table.tsx

Lines changed: 63 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"use client";
22

33
import { ShortAddress } from "@/components/short-address";
4+
import { Button } from "@/components/ui/button";
45
import { Card, CardContent } from "@/components/ui/card";
56
import {
67
Select,
@@ -18,63 +19,96 @@ import {
1819
TableRow,
1920
} from "@/components/ui/table/table";
2021
import { TableHeadCell } from "@/components/ui/table/table-head-cell";
21-
import type { ClientId } from "@/server/db/schema";
22+
import { DEFAULT_CLIENT_ID_DOMAIN } from "@/lib/constants/ecommerce";
23+
import type { EcommerceClient } from "@/server/db/schema";
2224
import { format } from "date-fns";
2325
import { CreditCard, Filter } from "lucide-react";
26+
import { Edit, Trash2 } from "lucide-react";
2427
import { useState } from "react";
28+
import { DeleteEcommerceClient } from "./delete-client";
29+
import { EditEcommerceClient } from "./edit-client";
2530

26-
interface ClientIdsTableProps {
27-
clientIds: ClientId[];
31+
interface EcommerceClientsTableProps {
32+
ecommerceClients: EcommerceClient[];
2833
}
2934

30-
const ClientIdTableColumns = () => (
35+
const EcommerceClientTableColumns = () => (
3136
<TableRow className="hover:bg-transparent border-none">
3237
<TableHeadCell>Created Date</TableHeadCell>
3338
<TableHeadCell>Label</TableHeadCell>
3439
<TableHeadCell>Domain</TableHeadCell>
35-
<TableHeadCell>Client ID</TableHeadCell>
40+
<TableHeadCell>RN Client ID</TableHeadCell>
3641
<TableHeadCell>Fee Address</TableHeadCell>
3742
<TableHeadCell>Fee Percentage</TableHeadCell>
43+
<TableHeadCell className="text-right">Actions</TableHeadCell>
3844
</TableRow>
3945
);
4046

41-
const ClientIdRow = ({ clientId }: { clientId: ClientId }) => {
47+
const EcommerceClientRow = ({
48+
ecommerceClient,
49+
}: { ecommerceClient: EcommerceClient }) => {
50+
const canShowActions = ecommerceClient.domain !== DEFAULT_CLIENT_ID_DOMAIN;
51+
4252
return (
4353
<TableRow className="hover:bg-zinc-50/50">
4454
<TableCell>
45-
{clientId.createdAt
46-
? format(new Date(clientId.createdAt), "do MMM yyyy")
55+
{ecommerceClient.createdAt
56+
? format(new Date(ecommerceClient.createdAt), "do MMM yyyy")
4757
: "N/A"}
4858
</TableCell>
49-
<TableCell className="font-medium">{clientId.label}</TableCell>
50-
<TableCell>{clientId.domain}</TableCell>
59+
<TableCell className="font-medium">{ecommerceClient.label}</TableCell>
60+
<TableCell>{ecommerceClient.domain}</TableCell>
5161
<TableCell>
52-
<ShortAddress address={clientId.clientId} />
62+
<ShortAddress address={ecommerceClient.rnClientId} />
5363
</TableCell>
5464
<TableCell>
55-
{clientId.feeAddress ? (
56-
<ShortAddress address={clientId.feeAddress} />
65+
{ecommerceClient.feeAddress ? (
66+
<ShortAddress address={ecommerceClient.feeAddress} />
5767
) : (
5868
<span className="text-zinc-500">-</span>
5969
)}
6070
</TableCell>
6171
<TableCell>
62-
{clientId.feePercentage ? (
63-
<span>{clientId.feePercentage}%</span>
72+
{ecommerceClient.feePercentage ? (
73+
<span>{ecommerceClient.feePercentage}%</span>
6474
) : (
6575
<span className="text-zinc-500">-</span>
6676
)}
6777
</TableCell>
78+
<TableCell>
79+
<div className="flex items-center gap-1">
80+
{canShowActions && (
81+
<>
82+
<EditEcommerceClient ecommerceClient={ecommerceClient}>
83+
<Button variant="ghost" size="sm" className="h-8 w-8 p-0">
84+
<Edit className="h-4 w-4" />
85+
</Button>
86+
</EditEcommerceClient>
87+
<DeleteEcommerceClient ecommerceClient={ecommerceClient}>
88+
<Button
89+
variant="ghost"
90+
size="sm"
91+
className="h-8 w-8 p-0 hover:bg-red-50"
92+
>
93+
<Trash2 className="h-4 w-4 text-red-500" />
94+
</Button>
95+
</DeleteEcommerceClient>
96+
</>
97+
)}
98+
</div>
99+
</TableCell>
68100
</TableRow>
69101
);
70102
};
71103

72-
export function ClientIdsTable({ clientIds }: ClientIdsTableProps) {
104+
export function EcommerceClientsTable({
105+
ecommerceClients,
106+
}: EcommerceClientsTableProps) {
73107
const [activeClient, setActiveClient] = useState<string | null>(null);
74108

75-
const filteredClientIds = activeClient
76-
? clientIds.filter(({ clientId }) => clientId === activeClient)
77-
: clientIds;
109+
const filteredEcommerceClients = activeClient
110+
? ecommerceClients.filter(({ id }) => id === activeClient)
111+
: ecommerceClients;
78112

79113
return (
80114
<div className="space-y-6 w-full">
@@ -96,8 +130,8 @@ export function ClientIdsTable({ clientIds }: ClientIdsTableProps) {
96130
</SelectTrigger>
97131
<SelectContent>
98132
<SelectItem value="all">All Clients</SelectItem>
99-
{clientIds.map(({ clientId, label }) => (
100-
<SelectItem key={clientId} value={clientId}>
133+
{ecommerceClients.map(({ id, label }) => (
134+
<SelectItem key={id} value={id}>
101135
{label}
102136
</SelectItem>
103137
))}
@@ -109,12 +143,12 @@ export function ClientIdsTable({ clientIds }: ClientIdsTableProps) {
109143
<CardContent className="p-0">
110144
<Table>
111145
<TableHeader>
112-
<ClientIdTableColumns />
146+
<EcommerceClientTableColumns />
113147
</TableHeader>
114148
<TableBody>
115-
{filteredClientIds.length === 0 ? (
149+
{filteredEcommerceClients.length === 0 ? (
116150
<TableRow>
117-
<TableCell colSpan={6} className="p-0">
151+
<TableCell colSpan={7} className="p-0">
118152
<EmptyState
119153
icon={<CreditCard className="h-6 w-6 text-zinc-600" />}
120154
title="No client IDs"
@@ -127,8 +161,11 @@ export function ClientIdsTable({ clientIds }: ClientIdsTableProps) {
127161
</TableCell>
128162
</TableRow>
129163
) : (
130-
filteredClientIds.map((clientId) => (
131-
<ClientIdRow key={clientId.id} clientId={clientId} />
164+
filteredEcommerceClients.map((ecommerceClient) => (
165+
<EcommerceClientRow
166+
key={ecommerceClient.id}
167+
ecommerceClient={ecommerceClient}
168+
/>
132169
))
133170
)}
134171
</TableBody>

0 commit comments

Comments
 (0)