Skip to content

Commit 18f24fb

Browse files
Added import from google sheets table
1 parent 470dbf8 commit 18f24fb

File tree

24 files changed

+979
-382
lines changed

24 files changed

+979
-382
lines changed

package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
"@eslint/eslintrc": "^3",
2727
"@tailwindcss/postcss": "^4",
2828
"@types/node": "^20",
29+
"@types/papaparse": "^5.3.16",
2930
"@types/react": "^19",
3031
"@types/react-dom": "^19",
3132
"eslint": "^9",

src/app/(user)/achievements/page.tsx

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,14 +26,16 @@ export default function AchievementsPage() {
2626
throw new Error("Failed to fetch achievements");
2727
}
2828
const data: InventoryItem[] = await response.json();
29-
const parsedData: Achievement[] = data.map((item: InventoryItem) => ({
30-
id: item.item_inventory_itemToitem.id,
31-
title: item.item_inventory_itemToitem.title,
32-
description:
33-
item.item_inventory_itemToitem.description || null,
34-
price: item.item_inventory_itemToitem.price,
35-
quantity: item.quantity || 1,
36-
}));
29+
const parsedData: Achievement[] = data.map(
30+
(item: InventoryItem) => ({
31+
id: item.item_inventory_itemToitem.id,
32+
title: item.item_inventory_itemToitem.title,
33+
description:
34+
item.item_inventory_itemToitem.description || null,
35+
price: item.item_inventory_itemToitem.price,
36+
quantity: item.quantity || 1,
37+
})
38+
);
3739
setAchievements(parsedData);
3840
} catch (error) {
3941
console.error(error);

src/app/(user)/marketplace/add/page.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,14 @@ import FormGroup from "@/components/form/FormGroup";
1313
import FormInput from "@/components/form/FormInput";
1414
import FormSubtitle from "@/components/form/FormSubtitle";
1515

16-
1716
const createItemSchema = z.object({
1817
title: z.string().min(1, { message: "Title is required" }),
1918
description: z.string().optional(),
2019
price: z
2120
.string()
2221
.min(1, { message: "Price is required" })
2322
.refine((val) => !isNaN(Number(val)) && Number(val) >= 0, {
24-
message: "Price must be a positive number"
23+
message: "Price must be a positive number",
2524
}),
2625
});
2726

@@ -46,7 +45,7 @@ export default function AddItemPage() {
4645
try {
4746
const submitData = {
4847
...data,
49-
price: Number(data.price)
48+
price: Number(data.price),
5049
};
5150
const response = await fetch("/api/marketplace/items", {
5251
method: "POST",

src/app/(user)/marketplace/item/[id]/ItemClientPage.tsx

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

3-
import { useSession } from 'next-auth/react';
3+
import { useSession } from "next-auth/react";
44
import React, { useState, useEffect } from "react";
55
import Alert from "@/components/Alert";
66
import Button from "@/components/Button";
@@ -23,7 +23,6 @@ export default function ItemPageClient({ id }: ItemPageClientProps) {
2323
const [buyError, setBuyError] = useState<string | null>(null);
2424
const [buySuccess, setBuySuccess] = useState<string | null>(null);
2525

26-
2726
const router = useRouter();
2827
const { balance, refreshBalance } = useBalance();
2928

@@ -103,61 +102,56 @@ export default function ItemPageClient({ id }: ItemPageClientProps) {
103102
return (
104103
<>
105104
{item && <PageTitle>{item.title} </PageTitle>}
106-
<div className="flex justify-center items-center" >
107-
<div className="w-full md:w-1/2" >
105+
<div className="flex justify-center items-center">
106+
<div className="w-full md:w-1/2">
108107
{item && (
109108
<>
110-
<div className="text-lg" >
111-
<span className="font-bold" > Description: </span>{" "}
109+
<div className="text-lg">
110+
<span className="font-bold">
111+
{" "}
112+
Description:{" "}
113+
</span>{" "}
112114
{item.description}
113115
</div>
114-
< div className="text-lg" >
115-
<span className="font-bold" > Price: </span> $
116+
<div className="text-lg">
117+
<span className="font-bold"> Price: </span> $
116118
{item.price.toFixed(2)}
117119
</div>
118-
< div className="text-lg" >
119-
<span className="font-bold" > Owner: </span>{" "}
120+
<div className="text-lg">
121+
<span className="font-bold"> Owner: </span>{" "}
120122
{item.user.name}
121123
</div>
122124
</>
123125
)}
124-
{
125-
session &&
126+
{session &&
126127
item &&
127128
parseInt(session.user.id) !== item.owner &&
128129
item.on_marketplace && (
129-
<div className="mt-4" >
130+
<div className="mt-4">
130131
<Button
131132
onClick={handleBuy}
132-
disabled={!canAfford || isBuying
133-
}
133+
disabled={!canAfford || isBuying}
134134
>
135135
{isBuying ? "Processing..." : "Buy Now"}
136136
</Button>
137-
{
138-
!canAfford && (
139-
<p className="text-red-500 text-sm mt-2" >
140-
You don & apos;t have enough balance to buy
141-
this item.
142-
</p>
143-
)
144-
}
145-
{
146-
buyError && (
147-
<Alert
148-
variant="danger"
149-
message={buyError}
150-
/>
151-
)
152-
}
153-
{
154-
buySuccess && (
155-
<Alert
156-
variant="success"
157-
message={buySuccess}
158-
/>
159-
)
160-
}
137+
{!canAfford && (
138+
<p className="text-red-500 text-sm mt-2">
139+
You don & apos;t have enough balance to
140+
buy this item.
141+
</p>
142+
)}
143+
{buyError && (
144+
<Alert
145+
variant="danger"
146+
message={buyError}
147+
/>
148+
)}
149+
{buySuccess && (
150+
<Alert
151+
variant="success"
152+
message={buySuccess}
153+
/>
154+
)}
161155
</div>
162156
)}
163157
</div>

src/app/(user)/marketplace/item/[id]/page.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import React from "react";
22
import ItemPageClient from "./ItemClientPage";
33

4-
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
4+
export default async function Page({
5+
params,
6+
}: {
7+
params: Promise<{ id: string }>;
8+
}) {
59
const { id } = await params;
610

711
return <ItemPageClient id={id} />;

src/app/(user)/transactions/page.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import Loader from "@/components/Loader";
99
import { TransactionWithUsers } from "@/lib/transactions";
1010

1111
export default function TransactionsPage() {
12-
const [transactions, setTransactions] = useState<TransactionWithUsers[]>([]);
12+
const [transactions, setTransactions] = useState<TransactionWithUsers[]>(
13+
[]
14+
);
1315
const [loading, setLoading] = useState(true);
1416
const [error, setError] = useState<string | null>(null);
1517
const { data: session } = useSession();

src/app/(user)/transfer/page.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ export default function TransferPage() {
3131
const { data: session } = useSession();
3232
const { refreshBalance, balance } = useBalance();
3333

34-
3534
const transferSchema = useMemo(() => {
3635
return z.object({
3736
recipient: z.string().min(1, "Recipient is required"),
@@ -71,7 +70,8 @@ export default function TransferPage() {
7170
if (session?.user?.id) {
7271
setUsers(
7372
data.filter(
74-
(user: User) => user.id != parseInt(session.user?.id)
73+
(user: User) =>
74+
user.id != parseInt(session.user?.id)
7575
)
7676
);
7777
} else {
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
"use client";
2+
3+
import { useForm, FormProvider } from "react-hook-form";
4+
import { zodResolver } from "@hookform/resolvers/zod";
5+
import { z } from "zod";
6+
import FormContainer from "@/components/form/FormContainer";
7+
import FormGroup from "@/components/form/FormGroup";
8+
import FormInput from "@/components/form/FormInput";
9+
import FormCheckbox from "@/components/form/FormCheckbox";
10+
import FormSubmit from "@/components/form/FormSubmit";
11+
import FormTitle from "@/components/form/FormTitle";
12+
13+
const importSchema = z.object({
14+
sheetKey: z.string().min(1, { message: "Sheet key is required" }),
15+
sheetName: z.string().min(1, { message: "Sheet name is required" }),
16+
importUserItems: z.boolean(),
17+
importItems: z.boolean(),
18+
});
19+
20+
export type ImportSchema = z.infer<typeof importSchema>;
21+
22+
interface ImportFormProps {
23+
onFormSubmit: (data: ImportSchema) => Promise<void>;
24+
isSubmitting: boolean;
25+
}
26+
27+
export default function ImportForm({
28+
onFormSubmit,
29+
isSubmitting,
30+
}: ImportFormProps) {
31+
const methods = useForm<ImportSchema>({
32+
resolver: zodResolver(importSchema),
33+
defaultValues: {
34+
sheetKey: "",
35+
sheetName: "",
36+
importUserItems: true,
37+
importItems: true,
38+
},
39+
});
40+
41+
const { handleSubmit } = methods;
42+
43+
return (
44+
<FormProvider {...methods}>
45+
<FormContainer onSubmit={handleSubmit(onFormSubmit)}>
46+
<FormTitle>Import data</FormTitle>
47+
<FormGroup>
48+
<FormInput
49+
name="sheetKey"
50+
label="Google Sheets Key"
51+
required
52+
/>
53+
</FormGroup>
54+
<FormGroup>
55+
<FormInput name="sheetName" label="Sheet Name" required />
56+
</FormGroup>
57+
<FormGroup>
58+
<FormCheckbox
59+
name="importUserItems"
60+
label="Import User Items"
61+
defaultChecked={true}
62+
/>
63+
</FormGroup>
64+
<FormGroup>
65+
<FormCheckbox
66+
name="importItems"
67+
label="Import Items"
68+
defaultChecked={true}
69+
/>
70+
</FormGroup>
71+
<FormSubmit isLoading={isSubmitting}>Try Import</FormSubmit>
72+
</FormContainer>
73+
</FormProvider>
74+
);
75+
}

0 commit comments

Comments
 (0)