diff --git a/frontend/public/images/placeholder.png b/frontend/public/images/placeholder.png new file mode 100644 index 0000000..8910fdd Binary files /dev/null and b/frontend/public/images/placeholder.png differ diff --git a/frontend/src/components/layout/data/sidebar-data.ts b/frontend/src/components/layout/data/sidebar-data.ts index b066828..cf906db 100644 --- a/frontend/src/components/layout/data/sidebar-data.ts +++ b/frontend/src/components/layout/data/sidebar-data.ts @@ -1,5 +1,6 @@ import { IconBrowserCheck, + IconBuildingStore, IconCoin, IconForklift, IconHelp, @@ -18,28 +19,6 @@ import { AudioWaveform, Command, GalleryVerticalEnd } from "lucide-react"; import { type SidebarData } from "../types"; export const sidebarData: SidebarData = { - user: { - name: "satnaing", - email: "satnaingdev@gmail.com", - avatar: "/avatars/shadcn.jpg" - }, - teams: [ - { - name: "SwagShop Admin", - logo: Command, - plan: "Vite + ShadcnUI" - }, - { - name: "Acme Inc", - logo: GalleryVerticalEnd, - plan: "Enterprise" - }, - { - name: "Acme Corp.", - logo: AudioWaveform, - plan: "Startup" - } - ], navGroups: [ { title: "Dashboard", @@ -49,6 +28,11 @@ export const sidebarData: SidebarData = { url: "/dashboard", icon: IconLayoutDashboard }, + { + title: "Shop", + url: "/dashboard/shop", + icon: IconBuildingStore + }, { title: "Products", url: "/dashboard/products", diff --git a/frontend/src/components/layout/types.ts b/frontend/src/components/layout/types.ts index 235b707..00a7f9a 100644 --- a/frontend/src/components/layout/types.ts +++ b/frontend/src/components/layout/types.ts @@ -1,17 +1,5 @@ import { LinkProps } from "@tanstack/react-router"; -interface User { - name: string; - email: string; - avatar: string; -} - -interface Team { - name: string; - logo: React.ElementType; - plan: string; -} - interface BaseNavItem { title: string; badge?: string; @@ -36,8 +24,6 @@ interface NavGroup { } interface SidebarData { - user: User; - teams: Team[]; navGroups: NavGroup[]; } diff --git a/frontend/src/pages/dashboard/index.tsx b/frontend/src/pages/dashboard/index.tsx index d9e2b0e..5965d7a 100644 --- a/frontend/src/pages/dashboard/index.tsx +++ b/frontend/src/pages/dashboard/index.tsx @@ -20,7 +20,7 @@ export default function Dashboard() { <> {/* ===== Top Heading ===== */}
- +
diff --git a/frontend/src/pages/products/index.tsx b/frontend/src/pages/products/index.tsx index c64b113..67ab6a0 100644 --- a/frontend/src/pages/products/index.tsx +++ b/frontend/src/pages/products/index.tsx @@ -62,10 +62,10 @@ export default function Products() {

- App Integrations + Products

- Here's a list of your apps for the integration! + Here's a list of your products!

diff --git a/frontend/src/pages/settings/security/index.tsx b/frontend/src/pages/settings/security/index.tsx index e69de29..18c4c26 100644 --- a/frontend/src/pages/settings/security/index.tsx +++ b/frontend/src/pages/settings/security/index.tsx @@ -0,0 +1,10 @@ +import ContentSection from "../components/content-section"; +import PasswordChangeForm from "./security-form"; + +export default function SettingsSecurity() { + return ( + + + + ); +} diff --git a/frontend/src/pages/settings/security/security-form.tsx b/frontend/src/pages/settings/security/security-form.tsx index e69de29..6f35176 100644 --- a/frontend/src/pages/settings/security/security-form.tsx +++ b/frontend/src/pages/settings/security/security-form.tsx @@ -0,0 +1,116 @@ +import { z } from "zod"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { Button } from "@/components/ui/button"; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage +} from "@/components/ui/form"; +import { PasswordInput } from "@/components/password-input"; +import { toast } from "@/hooks/useToast"; + +const passwordChangeSchema = z + .object({ + oldPassword: z.string().min(1, { + message: "Please enter your existing password" + }), + newPassword: z + .string() + .min(1, { message: "Please enter your new password" }) + .min(8, { message: "Password must be at least 8 characters long" }) + .max(128, { message: "Password must be at most 128 characters long" }) + .refine((password) => /[A-Z]/.test(password), { + message: "Password must contain at least one uppercase letter" + }) + .refine((password) => /[a-z]/.test(password), { + message: "Password must contain at least one lowercase letter" + }) + .refine((password) => /\d/.test(password), { + message: "Password must contain at least one number" + }) + .refine((password) => /[@$!%*?&]/.test(password), { + message: + "Password must contain at least one special character (@, $, !, %, *, ?, &)" + }), + confirmNewPassword: z.string().min(1, { + message: "Please confirm your new password" + }) + }) + .refine((data) => data.newPassword === data.confirmNewPassword, { + message: "Passwords don't match.", + path: ["confirmNewPassword"] + }); + +type PasswordChangeFormValues = z.infer; + +export default function PasswordChangeForm() { + const form = useForm({ + resolver: zodResolver(passwordChangeSchema), + defaultValues: { + oldPassword: "", + newPassword: "", + confirmNewPassword: "" + } + }); + + function onSubmit(data: PasswordChangeFormValues) { + toast({ + title: "Password Changed (MOCK)", + description: "Your password has been updated." + }); + } + + return ( +
+ + ( + + Existing Password + + + + + + )} + /> + ( + + New Password + + + + + + )} + /> + ( + + Confirm New Password + + + + + + )} + /> + + + + ); +} diff --git a/frontend/src/pages/shop/components/shop-about-form.tsx b/frontend/src/pages/shop/components/shop-about-form.tsx new file mode 100644 index 0000000..eb5ccdf --- /dev/null +++ b/frontend/src/pages/shop/components/shop-about-form.tsx @@ -0,0 +1,241 @@ +import { z } from "zod"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { Button } from "@/components/ui/button"; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage +} from "@/components/ui/form"; +import { Textarea } from "@/components/ui/textarea"; +import { PhoneInput } from "@/components/ui/phone-number-input"; +import { Input } from "@/components/ui/input"; +import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card"; +import { ScrollArea } from "@/components/ui/scroll-area"; + +const shopAboutSchema = z.object({ + name: z.string().min(1, "Name is required"), + description: z.string().min(1, "Description is required"), + currency: z.string().min(1, "Currency is required"), + contact_email: z.string().email("Invalid email"), + contact_phone_number: z.string().min(1, "Phone number is required"), + address: z.object({ + street: z.string(), + city: z.string(), + state: z.string().optional(), + postal_code: z.string(), + country: z.string() + }), + status: z.enum(["active", "inactive", "suspended"]) +}); + +type ShopAboutFormValues = z.infer; + +export function ShopAboutForm() { + const defaultValues: ShopAboutFormValues = { + name: "My Shop", + description: "This is a sample shop description.", + currency: "USD", + contact_email: "user@example.com", + contact_phone_number: "+266018975510", + address: { + street: "123 Main St", + city: "Metropolis", + state: "", + postal_code: "12345", + country: "USA" + }, + status: "inactive" + }; + + const form = useForm({ + resolver: zodResolver(shopAboutSchema), + defaultValues, + mode: "onChange" + }); + + function onSubmit(data: ShopAboutFormValues) { + console.log("Submitted shop about data:", data); + } + + return ( + +
+ + + + Basic Details + + + ( + + Shop Name + + + + + + )} + /> + ( + + Currency + + + + + + )} + /> + ( + + Description + +