Skip to content

Commit

Permalink
Update brands section and implement add new brand form
Browse files Browse the repository at this point in the history
  • Loading branch information
pjborowiecki committed Dec 23, 2023
1 parent 479261e commit 8040743
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 2 deletions.
9 changes: 9 additions & 0 deletions src/actions/inventory/brands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"use server"

import { type addBrandSchema } from "@/validations/inventory"
import type { z } from "zod"

export async function addNewBrand(input: z.infer<typeof addBrandSchema>) {
console.log(input.name)
return "success"
}
29 changes: 28 additions & 1 deletion src/app/(app)/app/inventory/brands/new-brand/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,30 @@
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card"
import { AddBrandForm } from "@/components/forms/inventory/brands/add-brand-form"
import { SubSubHeader } from "@/components/nav/subsubheader"

export default function AppInventoryBrandsNewBrandPage(): JSX.Element {
return <div className="p-5">App Inventory Brands NewBrand Page</div>
return (
<div>
<SubSubHeader />
<div className="p-5">
<Card className="max-w-6xl rounded-md bg-tertiary">
<CardHeader className="px-5 pt-5">
<CardTitle className="text-2xl">New Brand</CardTitle>
<CardDescription className="text-base">
Add new brand
</CardDescription>
</CardHeader>
<CardContent className="px-5 pt-2">
<AddBrandForm />
</CardContent>
</Card>
</div>
</div>
)
}
9 changes: 8 additions & 1 deletion src/app/(app)/app/inventory/brands/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
import { BrandsSubheader } from "@/components/inventory/subheaders/brands-subheader"

export default function AppInventoryBrandsPage(): JSX.Element {
return <div className="p-5">App Inventory Brands Page</div>
return (
<div>
<BrandsSubheader />
<div className="p-5">App Inventory Brands Page</div>
</div>
)
}
106 changes: 106 additions & 0 deletions src/components/forms/inventory/brands/add-brand-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
"use client"

import React from "react"
import Link from "next/link"
import { useRouter } from "next/navigation"
import { addNewBrand } from "@/actions/inventory/brands"
import { addBrandSchema } from "@/validations/inventory"
import { zodResolver } from "@hookform/resolvers/zod"
import { useForm } from "react-hook-form"
import type { z } from "zod"

import { useToast } from "@/hooks/use-toast"
import { cn } from "@/lib/utils"
import { Button, buttonVariants } from "@/components/ui/button"
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form"
import { Input } from "@/components/ui/input"
import { Icons } from "@/components/icons"

type AddBrandFormInputs = z.infer<typeof addBrandSchema>

export function AddBrandForm(): JSX.Element {
const { toast } = useToast()
const router = useRouter()
const [isPending, startTransition] = React.useTransition()

const form = useForm<AddBrandFormInputs>({
resolver: zodResolver(addBrandSchema),
defaultValues: {
name: "",
},
})

function onSubmit(formData: AddBrandFormInputs) {
startTransition(async () => {
try {
const response = await addNewBrand(formData)

if (response === "success") {
toast({ title: "Success!", description: "New category added" })
}

router.push("/app/inventory/categories")
} catch (error) {
toast({
title: "Something wend wrong",
description: "Please try again",
variant: "destructive",
})
}
})
}

return (
<Form {...form}>
<form
className="grid w-full gap-5"
onSubmit={(...args) => void form.handleSubmit(onSubmit)(...args)}
>
<FormField
control={form.control}
name="name"
render={({ field }) => (
<FormItem className="w-1/2">
<FormLabel>Name</FormLabel>
<FormControl>
<Input type="text" placeholder="Brand name" {...field} />
</FormControl>
<FormMessage className="pt-2 sm:text-sm" />
</FormItem>
)}
/>

<div className=" flex items-center gap-2 pt-2">
<Button disabled={isPending} aria-label="Add Brand" className="w-fit">
{isPending ? (
<>
<Icons.spinner
className="mr-2 h-4 w-4 animate-spin"
aria-hidden="true"
/>
<span>Adding...</span>
</>
) : (
<span>Add Brand</span>
)}
<span className="sr-only">Add Brand</span>
</Button>

<Link
href="/app/inventory/brands"
className={cn(buttonVariants({ variant: "ghost" }), "w-fit")}
>
Cancel
</Link>
</div>
</form>
</Form>
)
}
27 changes: 27 additions & 0 deletions src/components/inventory/subheaders/brands-subheader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Link from "next/link"

import { cn } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button"
import { CustomTooltip } from "@/components/custom-tooltip"
import { Icons } from "@/components/icons"
import { InstantHelperMenu } from "@/components/nav/app/menus/instant-helper-menu"

export function BrandsSubheader(): JSX.Element {
return (
<div className="flex h-20 w-full items-center justify-end border-b bg-tertiary px-5">
<div className="flex items-center gap-2">
<CustomTooltip text="Add New Brand">
<Link
href="/app/inventory/brands/new-brand"
className={cn(buttonVariants(), "gap-1")}
aria-label="Add new brand"
>
<Icons.plus aria-hidden="true" className="h-4 w-4" />
<span>New Brand</span>
</Link>
</CustomTooltip>
<InstantHelperMenu />
</div>
</div>
)
}
4 changes: 4 additions & 0 deletions src/validations/inventory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@ export const addUnitSchema = z.object({
name: z.string(),
abbreviation: z.string(),
})

export const addBrandSchema = z.object({
name: z.string(),
})

0 comments on commit 8040743

Please sign in to comment.