Skip to content

Commit

Permalink
Add ShippingInformationForm component and use it on the setting page
Browse files Browse the repository at this point in the history
  • Loading branch information
andrii-balitskyi committed Oct 17, 2024
1 parent 9666d54 commit b942a5d
Show file tree
Hide file tree
Showing 5 changed files with 178 additions and 1 deletion.
Binary file modified bun.lockb
Binary file not shown.
12 changes: 11 additions & 1 deletion fake-snippets-api/tests/fixtures/get-test-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,17 @@ export const getTestServer = async (): Promise<TestFixture> => {
}

const seedDatabase = (db: DbClient) => {
const account = db.addAccount({ github_username: "testuser" })
const account = db.addAccount({
github_username: "testuser",
shippingInfo: {
fullName: "Test User",
address: "123 Test St",
city: "Testville",
state: "NY",
zipCode: "10001",
country: "United States",
},
})
const order = db.addOrder({
account_id: account.account_id,
is_draft: true,
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
"@types/ms": "^0.7.34",
"@typescript/ata": "^0.9.7",
"@valtown/codemirror-ts": "^2.2.0",
"change-case": "^5.4.4",
"circuit-json": "^0.0.85",
"circuit-json-to-bom-csv": "^0.0.6",
"circuit-json-to-gerber": "^0.0.12",
Expand Down
155 changes: 155 additions & 0 deletions src/components/ShippingInformationForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import React, { useReducer, useEffect } from "react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { useToast } from "@/hooks/use-toast"
import { useAxios } from "@/hooks/use-axios"
import { useQuery, useMutation, useQueryClient } from "react-query"
import { Loader2 } from "lucide-react"
import { sentenceCase } from "change-case"

type ShippingInfo = {
fullName: string
address: string
city: string
state: string
zipCode: string
country: string
}

type Action =
| { type: "SET_FIELD"; field: keyof ShippingInfo; value: string }
| { type: "SET_ALL"; payload: ShippingInfo }

const initialState: ShippingInfo = {
fullName: "",
address: "",
zipCode: "",
country: "",
city: "",
state: "",
}

const shippingPlaceholders: ShippingInfo = {
fullName: "Enter your full name",
address: "Enter your street address",
zipCode: "Enter your zip code",
country: "Enter your country",
city: "Enter your city",
state: "Enter your state",
}

const ShippingInformationForm: React.FC = () => {
const [form, setField] = useReducer(
(state: ShippingInfo, action: Action): ShippingInfo => {
switch (action.type) {
case "SET_FIELD":
return { ...state, [action.field]: action.value }
case "SET_ALL":
return action.payload
default:
return state
}
},
initialState,
)
const { toast } = useToast()
const axios = useAxios()
const queryClient = useQueryClient()

const { data: account, isLoading: isLoadingAccount } = useQuery(
"account",
async () => {
const response = await axios.get("/accounts/get")
return response.data.account
},
)

const updateShippingMutation = useMutation(
(shippingInfo: ShippingInfo) =>
axios.post("/accounts/update", { shippingInfo }),
{
onSuccess: () => {
queryClient.invalidateQueries("account")
toast({
title: "Success",
description: "Shipping information updated successfully",
})
},
onError: () => {
toast({
title: "Error",
description: "Failed to update shipping information",
variant: "destructive",
})
},
},
)

useEffect(() => {
if (account?.shippingInfo) {
setField({ type: "SET_ALL", payload: account.shippingInfo })
}
}, [account])

const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault()
updateShippingMutation.mutate(form)
}

if (isLoadingAccount) {
return (
<div className="flex justify-center items-center h-64">
<Loader2 className="w-8 h-8 animate-spin" />
</div>
)
}

const fieldOrder: (keyof ShippingInfo)[] = [
"fullName",
"address",
"zipCode",
"country",
"city",
"state",
]

return (
<form onSubmit={handleSubmit} className="space-y-4">
{fieldOrder.map((key) => (
<div key={key}>
<label
htmlFor={key}
className="block text-sm font-medium text-gray-700"
>
{sentenceCase(key)}
</label>
<Input
id={key}
value={form[key]}
onChange={(e) =>
setField({
type: "SET_FIELD",
field: key,
value: e.target.value,
})
}
placeholder={shippingPlaceholders[key]}
disabled={updateShippingMutation.isLoading}
/>
</div>
))}
<Button type="submit" disabled={updateShippingMutation.isLoading}>
{updateShippingMutation.isLoading ? (
<>
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
Updating...
</>
) : (
"Update"
)}
</Button>
</form>
)
}

export default ShippingInformationForm
11 changes: 11 additions & 0 deletions src/pages/settings.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
import Header from "@/components/Header"
import Footer from "@/components/Footer"
import ShippingInformationForm from "@/components/ShippingInformationForm"

export const SettingsPage = () => {
return (
<div>
<Header />
<div className="container mx-auto px-4 py-8">
<h1 className="text-3xl font-bold mb-6">Settings</h1>
<div className="flex">
<div className="w-1/2 pr-4">
<div className="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
<h2 className="text-2xl font-semibold mb-4">
Shipping Information
</h2>
<ShippingInformationForm />
</div>
</div>
</div>
</div>
<Footer />
</div>
Expand Down

0 comments on commit b942a5d

Please sign in to comment.