From f8e657c17436c3f1bf593ed78adf32f2868689e7 Mon Sep 17 00:00:00 2001
From: "ALMAZROUEI Shamma (2021) WKIS203"
 <shamma.almazrouei.2021@live.rhul.ac.uk>
Date: Tue, 11 Mar 2025 17:04:34 +0530
Subject: [PATCH] Build register page

---
 golden-crust-bakery/package-lock.json         |  31 ++
 golden-crust-bakery/package.json              |   1 +
 .../src/components/ui/checkbox.jsx            |  22 ++
 golden-crust-bakery/src/main.jsx              |  15 +-
 golden-crust-bakery/src/pages/Register.jsx    | 301 ++++++++++++++++++
 5 files changed, 365 insertions(+), 5 deletions(-)
 create mode 100644 golden-crust-bakery/src/components/ui/checkbox.jsx
 create mode 100644 golden-crust-bakery/src/pages/Register.jsx

diff --git a/golden-crust-bakery/package-lock.json b/golden-crust-bakery/package-lock.json
index ddc8e9b..5b8061a 100644
--- a/golden-crust-bakery/package-lock.json
+++ b/golden-crust-bakery/package-lock.json
@@ -9,6 +9,7 @@
       "version": "0.0.0",
       "dependencies": {
         "@radix-ui/react-accordion": "^1.2.3",
+        "@radix-ui/react-checkbox": "^1.1.4",
         "@radix-ui/react-dialog": "^1.1.6",
         "@radix-ui/react-dropdown-menu": "^2.1.6",
         "@radix-ui/react-label": "^2.1.2",
@@ -1205,6 +1206,36 @@
         }
       }
     },
+    "node_modules/@radix-ui/react-checkbox": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.1.4.tgz",
+      "integrity": "sha512-wP0CPAHq+P5I4INKe3hJrIa1WoNqqrejzW+zoU0rOvo1b9gDEJJFl2rYfO1PYJUQCc2H1WZxIJmyv9BS8i5fLw==",
+      "license": "MIT",
+      "dependencies": {
+        "@radix-ui/primitive": "1.1.1",
+        "@radix-ui/react-compose-refs": "1.1.1",
+        "@radix-ui/react-context": "1.1.1",
+        "@radix-ui/react-presence": "1.1.2",
+        "@radix-ui/react-primitive": "2.0.2",
+        "@radix-ui/react-use-controllable-state": "1.1.0",
+        "@radix-ui/react-use-previous": "1.1.0",
+        "@radix-ui/react-use-size": "1.1.0"
+      },
+      "peerDependencies": {
+        "@types/react": "*",
+        "@types/react-dom": "*",
+        "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+        "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "@types/react-dom": {
+          "optional": true
+        }
+      }
+    },
     "node_modules/@radix-ui/react-collapsible": {
       "version": "1.1.3",
       "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.3.tgz",
diff --git a/golden-crust-bakery/package.json b/golden-crust-bakery/package.json
index 1921393..e9b80ea 100644
--- a/golden-crust-bakery/package.json
+++ b/golden-crust-bakery/package.json
@@ -11,6 +11,7 @@
   },
   "dependencies": {
     "@radix-ui/react-accordion": "^1.2.3",
+    "@radix-ui/react-checkbox": "^1.1.4",
     "@radix-ui/react-dialog": "^1.1.6",
     "@radix-ui/react-dropdown-menu": "^2.1.6",
     "@radix-ui/react-label": "^2.1.2",
diff --git a/golden-crust-bakery/src/components/ui/checkbox.jsx b/golden-crust-bakery/src/components/ui/checkbox.jsx
new file mode 100644
index 0000000..5e0c96b
--- /dev/null
+++ b/golden-crust-bakery/src/components/ui/checkbox.jsx
@@ -0,0 +1,22 @@
+import * as React from "react"
+import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
+import { Check } from "lucide-react"
+
+import { cn } from "@/lib/utils"
+
+const Checkbox = React.forwardRef(({ className, ...props }, ref) => (
+  <CheckboxPrimitive.Root
+    ref={ref}
+    className={cn(
+      "peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
+      className
+    )}
+    {...props}>
+    <CheckboxPrimitive.Indicator className={cn("flex items-center justify-center text-current")}>
+      <Check className="h-4 w-4" />
+    </CheckboxPrimitive.Indicator>
+  </CheckboxPrimitive.Root>
+))
+Checkbox.displayName = CheckboxPrimitive.Root.displayName
+
+export { Checkbox }
diff --git a/golden-crust-bakery/src/main.jsx b/golden-crust-bakery/src/main.jsx
index a92a05a..4a44fcb 100644
--- a/golden-crust-bakery/src/main.jsx
+++ b/golden-crust-bakery/src/main.jsx
@@ -10,8 +10,9 @@ import './index.css';
 import App from './App.jsx';
 import Landing from './pages/Landing';
 import About from './pages/About';
-import Contact from './pages/Contact';
+// import Contact from './pages/Contact';
 import Login from './pages/Login';
+import Register from './pages/Register';
 
 const router = createBrowserRouter([
   {
@@ -26,14 +27,18 @@ const router = createBrowserRouter([
         path: '/about',
         element: <About />,
       },
-      {
-        path: '/contact',
-        element: <Contact />,
-      },
+      // {
+      //   path: '/contact',
+      //   element: <Contact />,
+      // },
       {
         path: '/login',
         element: <Login />,
       },
+      {
+        path: '/register',
+        element: <Register />,
+      },
     ],
   },
 ]);
diff --git a/golden-crust-bakery/src/pages/Register.jsx b/golden-crust-bakery/src/pages/Register.jsx
new file mode 100644
index 0000000..3e39f9c
--- /dev/null
+++ b/golden-crust-bakery/src/pages/Register.jsx
@@ -0,0 +1,301 @@
+import { useState } from 'react';
+import { useNavigate, Link } from 'react-router-dom';
+import { toast } from 'sonner';
+import { Cake, Lock, Mail, User } from 'lucide-react';
+
+import { useAuthStore } from '@/lib/authStore';
+
+import { Button } from '@/components/ui/button';
+import { Input } from '@/components/ui/input';
+import { Label } from '@/components/ui/label';
+import { Checkbox } from '@/components/ui/checkbox';
+
+export default function Register() {
+  const navigate = useNavigate();
+  const { login } = useAuthStore();
+
+  const [formData, setFormData] = useState({
+    name: '',
+    email: '',
+    password: '',
+    confirmPassword: '',
+    agreeTerms: false,
+  });
+
+  const [errors, setErrors] = useState({});
+  const [isSubmitting, setIsSubmitting] = useState(false);
+
+  const handleChange = (e) => {
+    const { name, value, type, checked } = e.target;
+    setFormData((prev) => ({
+      ...prev,
+      [name]: type === 'checkbox' ? checked : value,
+    }));
+
+    // Clear error when field is being edited
+    if (errors[name]) {
+      setErrors((prev) => ({
+        ...prev,
+        [name]: '',
+      }));
+    }
+  };
+
+  const validateForm = () => {
+    const newErrors = {};
+
+    if (!formData.name.trim()) newErrors.name = 'Name is required';
+
+    if (!formData.email.trim()) {
+      newErrors.email = 'Email is required';
+    } else if (!/\S+@\S+\.\S+/.test(formData.email)) {
+      newErrors.email = 'Email is invalid';
+    }
+
+    if (!formData.password) {
+      newErrors.password = 'Password is required';
+    } else if (formData.password.length < 6) {
+      newErrors.password = 'Password must be at least 6 characters';
+    }
+
+    if (formData.password !== formData.confirmPassword) {
+      newErrors.confirmPassword = 'Passwords do not match';
+    }
+
+    if (!formData.agreeTerms) {
+      newErrors.agreeTerms = 'You must agree to the terms and conditions';
+    }
+
+    setErrors(newErrors);
+    return Object.keys(newErrors).length === 0;
+  };
+
+  const handleSubmit = (e) => {
+    e.preventDefault();
+
+    if (!validateForm()) return;
+
+    setIsSubmitting(true);
+
+    // Simulate registration process
+    setTimeout(() => {
+      // Check if user already exists
+      const users = JSON.parse(localStorage.getItem('users') || '[]');
+      const userExists = users.some((user) => user.email === formData.email);
+
+      if (userExists) {
+        setErrors({
+          email: 'This email is already registered',
+        });
+        setIsSubmitting(false);
+        return;
+      }
+
+      // Create new user
+      const newUser = {
+        id: Date.now().toString(),
+        name: formData.name,
+        email: formData.email,
+        password: formData.password,
+      };
+
+      // Save to local storage
+      localStorage.setItem('users', JSON.stringify([...users, newUser]));
+
+      // Auto login
+      login({
+        id: newUser.id,
+        name: newUser.name,
+        email: newUser.email,
+      });
+
+      toast({
+        title: 'Registration Successful',
+        description: `Welcome to Golden Crust Bakery, ${newUser.name}!`,
+      });
+
+      setIsSubmitting(false);
+      navigate('/');
+    }, 1500);
+  };
+
+  return (
+    <div className='container mx-auto px-4 py-8 md:py-12'>
+      <div className='max-w-md mx-auto'>
+        <div className='text-center mb-8'>
+          <div className='mx-auto w-16 h-16 bg-pink-100 rounded-full flex items-center justify-center mb-4'>
+            <Cake className='h-8 w-8 text-pink-500' />
+          </div>
+          <h1 className='text-3xl font-bold text-gray-800 mb-2'>
+            Create an Account
+          </h1>
+          <p className='text-gray-600'>
+            Join Golden Crust Bakery to order delicious cakes
+          </p>
+        </div>
+
+        <div className='bg-white rounded-xl border shadow-sm overflow-hidden'>
+          <div className='p-6'>
+            <form onSubmit={handleSubmit} className='space-y-6'>
+              <div className='space-y-2'>
+                <Label htmlFor='name'>Full Name</Label>
+                <div className='relative'>
+                  <User className='absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-5 w-5' />
+                  <Input
+                    id='name'
+                    name='name'
+                    value={formData.name}
+                    onChange={handleChange}
+                    className={`pl-10 rounded-lg ${
+                      errors.name ? 'border-red-500' : 'border-gray-200'
+                    }`}
+                    placeholder='Peter Parker'
+                  />
+                </div>
+                {errors.name && (
+                  <p className='text-red-500 text-sm'>{errors.name}</p>
+                )}
+              </div>
+
+              <div className='space-y-2'>
+                <Label htmlFor='email'>Email Address</Label>
+                <div className='relative'>
+                  <Mail className='absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-5 w-5' />
+                  <Input
+                    id='email'
+                    name='email'
+                    type='email'
+                    value={formData.email}
+                    onChange={handleChange}
+                    className={`pl-10 rounded-lg ${
+                      errors.email ? 'border-red-500' : 'border-gray-200'
+                    }`}
+                    placeholder='yourname@email.com'
+                  />
+                </div>
+                {errors.email && (
+                  <p className='text-red-500 text-sm'>{errors.email}</p>
+                )}
+              </div>
+
+              <div className='space-y-2'>
+                <Label htmlFor='password'>Password</Label>
+                <div className='relative'>
+                  <Lock className='absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-5 w-5' />
+                  <Input
+                    id='password'
+                    name='password'
+                    type='password'
+                    value={formData.password}
+                    onChange={handleChange}
+                    className={`pl-10 rounded-lg ${
+                      errors.password ? 'border-red-500' : 'border-gray-200'
+                    }`}
+                    placeholder='********'
+                  />
+                </div>
+                {errors.password && (
+                  <p className='text-red-500 text-sm'>{errors.password}</p>
+                )}
+              </div>
+
+              <div className='space-y-2'>
+                <Label htmlFor='confirmPassword'>Confirm Password</Label>
+                <div className='relative'>
+                  <Lock className='absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-5 w-5' />
+                  <Input
+                    id='confirmPassword'
+                    name='confirmPassword'
+                    type='password'
+                    value={formData.confirmPassword}
+                    onChange={handleChange}
+                    className={`pl-10 rounded-lg ${
+                      errors.confirmPassword
+                        ? 'border-red-500'
+                        : 'border-gray-200'
+                    }`}
+                    placeholder='********'
+                  />
+                </div>
+                {errors.confirmPassword && (
+                  <p className='text-red-500 text-sm'>
+                    {errors.confirmPassword}
+                  </p>
+                )}
+              </div>
+
+              <div className='flex items-start space-x-2'>
+                <Checkbox
+                  id='agreeTerms'
+                  name='agreeTerms'
+                  checked={formData.agreeTerms}
+                  onCheckedChange={(checked) => {
+                    setFormData((prev) => ({
+                      ...prev,
+                      agreeTerms: checked,
+                    }));
+                    if (errors.agreeTerms) {
+                      setErrors((prev) => ({
+                        ...prev,
+                        agreeTerms: '',
+                      }));
+                    }
+                  }}
+                  className={errors.agreeTerms ? 'border-red-500' : ''}
+                />
+                <div className='grid gap-1.5 leading-none'>
+                  <label
+                    htmlFor='agreeTerms'
+                    className='text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70'
+                  >
+                    I agree to the{' '}
+                    <Link to='#' className='text-pink-600 hover:underline'>
+                      Terms of Service
+                    </Link>{' '}
+                    and{' '}
+                    <Link to='#' className='text-pink-600 hover:underline'>
+                      Privacy Policy
+                    </Link>
+                  </label>
+                  {errors.agreeTerms && (
+                    <p className='text-red-500 text-sm'>{errors.agreeTerms}</p>
+                  )}
+                </div>
+              </div>
+
+              <Button
+                type='submit'
+                disabled={isSubmitting}
+                className='w-full bg-pink-500 hover:bg-pink-600 text-white rounded-full py-6'
+              >
+                {isSubmitting ? 'Creating Account...' : 'Create Account'}
+              </Button>
+            </form>
+
+            <div className='mt-6 text-center'>
+              <p className='text-gray-600'>
+                Already have an account?{' '}
+                <Link
+                  to='/login'
+                  className='text-pink-600 hover:underline font-medium'
+                >
+                  Sign in
+                </Link>
+              </p>
+            </div>
+          </div>
+        </div>
+
+        <div className='mt-8 text-center'>
+          <Button
+            variant='ghost'
+            onClick={() => navigate('/')}
+            className='text-gray-600 hover:text-gray-800'
+          >
+            Return to Home
+          </Button>
+        </div>
+      </div>
+    </div>
+  );
+}
-- 
GitLab