diff --git a/package.json b/package.json
index 73f9a19..4845043 100644
--- a/package.json
+++ b/package.json
@@ -27,7 +27,8 @@
"react-dom": "19.0.0",
"react-icons": "5.4.0",
"tailwind-merge": "2.6.0",
- "tailwindcss-animate": "1.0.7"
+ "tailwindcss-animate": "1.0.7",
+ "zod": "3.24.1"
},
"devDependencies": {
"@commitlint/cli": "19.6.1",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7a7245e..bc26c96 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -47,6 +47,9 @@ importers:
tailwindcss-animate:
specifier: 1.0.7
version: 1.0.7(tailwindcss@3.4.17)
+ zod:
+ specifier: 3.24.1
+ version: 3.24.1
devDependencies:
'@commitlint/cli':
specifier: 19.6.1
@@ -2634,6 +2637,9 @@ packages:
resolution: {integrity: sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g==}
engines: {node: '>=12.20'}
+ zod@3.24.1:
+ resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==}
+
snapshots:
'@alloc/quick-lru@5.2.0': {}
@@ -5406,3 +5412,5 @@ snapshots:
yocto-queue@0.1.0: {}
yocto-queue@1.1.1: {}
+
+ zod@3.24.1: {}
diff --git a/src/app/(learners)/setting/page.tsx b/src/app/(learners)/setting/page.tsx
new file mode 100644
index 0000000..43e114b
--- /dev/null
+++ b/src/app/(learners)/setting/page.tsx
@@ -0,0 +1,29 @@
+import ProfileSettings from '@/components/learners/settings/ProfileSettings';
+
+/*
+ * ======================================================================
+ * Copyright (C) 2025 - lzaycoe (Lazy Code)
+ * ======================================================================
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * ======================================================================
+ */
+export default function Home() {
+ return (
+
+
+
+ );
+}
diff --git a/src/components/commons/learners/NavigationBar.tsx b/src/components/commons/learners/NavigationBar.tsx
new file mode 100644
index 0000000..1e1f0a0
--- /dev/null
+++ b/src/components/commons/learners/NavigationBar.tsx
@@ -0,0 +1,83 @@
+/*
+ * ======================================================================
+ * Copyright (C) 2025 - lzaycoe (Lazy Code)
+ * ======================================================================
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * ======================================================================
+ */
+'use client';
+
+import Link from 'next/link';
+import { usePathname } from 'next/navigation';
+import React from 'react';
+
+/*
+ * ======================================================================
+ * Copyright (C) 2025 - lzaycoe (Lazy Code)
+ * ======================================================================
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * ======================================================================
+ */
+
+export default function NavigationBar() {
+ const pathname = usePathname();
+ const navItems = [
+ { label: 'Dashboard', path: '/dashboard' },
+ { label: 'Courses', path: '/courses' },
+ { label: 'Teachers', path: '/teachers' },
+ { label: 'Message', path: '/message' },
+ { label: 'Wishlist', path: '/wishlist' },
+ { label: 'Purchase History', path: '/purchase-history' },
+ { label: 'Settings', path: '/setting' },
+ ];
+
+ return (
+
+
+
+
+
+ );
+}
diff --git a/src/components/commons/learners/Profile.tsx b/src/components/commons/learners/Profile.tsx
new file mode 100644
index 0000000..07c7fee
--- /dev/null
+++ b/src/components/commons/learners/Profile.tsx
@@ -0,0 +1,62 @@
+/*
+ * ======================================================================
+ * Copyright (C) 2025 - lzaycoe (Lazy Code)
+ * ======================================================================
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * ======================================================================
+ */
+import Image from 'next/image';
+
+export default function Profile() {
+ return (
+
+
+
+
+
+
+
Lazy Code
+
+ Web Designer & Best-Selling Instructor
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/learners/settings/PasswordChangeForm.tsx b/src/components/learners/settings/PasswordChangeForm.tsx
new file mode 100644
index 0000000..7006b96
--- /dev/null
+++ b/src/components/learners/settings/PasswordChangeForm.tsx
@@ -0,0 +1,130 @@
+/*
+ * ======================================================================
+ * Copyright (C) 2025 - lzaycoe (Lazy Code)
+ * ======================================================================
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * ======================================================================
+ */
+import { ZodError, z } from 'zod';
+
+const passwordSchema = z
+ .object({
+ currentPassword: z.string().min(1, 'Current password is required.'),
+ newPassword: z
+ .string()
+ .min(6, 'New password must be at least 6 characters long.'),
+ confirmPassword: z.string(),
+ })
+ .refine((data) => data.newPassword === data.confirmPassword, {
+ message: 'Passwords do not match.',
+ path: ['confirmPassword'],
+ });
+
+export default function PasswordChangeForm() {
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+
+ const formData = new FormData(e.currentTarget);
+ const currentPassword = formData.get('currentPassword') as string;
+ const newPassword = formData.get('newPassword') as string;
+ const confirmPassword = formData.get('confirmPassword') as string;
+
+ try {
+ passwordSchema.parse({ currentPassword, newPassword, confirmPassword });
+ console.log('Form submitted successfully:', {
+ currentPassword,
+ newPassword,
+ confirmPassword,
+ });
+ } catch (err) {
+ if (err instanceof ZodError) {
+ alert(err.errors[0].message);
+ }
+ }
+ };
+
+ return (
+
+ );
+}
diff --git a/src/components/learners/settings/ProfileForm.tsx b/src/components/learners/settings/ProfileForm.tsx
new file mode 100644
index 0000000..2f3200a
--- /dev/null
+++ b/src/components/learners/settings/ProfileForm.tsx
@@ -0,0 +1,151 @@
+/*
+ * ======================================================================
+ * Copyright (C) 2025 - lzaycoe (Lazy Code)
+ * ======================================================================
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * ======================================================================
+ */
+import { ZodError, z } from 'zod';
+
+// Schema validation using Zod
+const profileSchema = z.object({
+ firstName: z.string().min(1, 'First name is required.'),
+ lastName: z.string().min(1, 'Last name is required.'),
+ username: z.string().min(1, 'Username is required.'),
+ email: z.string().email('Invalid email address.'),
+ title: z.string().max(50, 'Title must be 50 characters or less.'),
+});
+
+export default function ProfileForm() {
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault();
+
+ const formData = new FormData(e.currentTarget);
+ const firstName = formData.get('firstName') as string;
+ const lastName = formData.get('lastName') as string;
+ const username = formData.get('username') as string;
+ const email = formData.get('email') as string;
+ const title = formData.get('title') as string;
+
+ try {
+ profileSchema.parse({ firstName, lastName, username, email, title });
+ console.log('Form submitted successfully:', {
+ firstName,
+ lastName,
+ username,
+ email,
+ title,
+ });
+ } catch (err) {
+ if (err instanceof ZodError) {
+ alert(err.errors[0].message);
+ }
+ }
+ };
+
+ return (
+
+ );
+}
diff --git a/src/components/learners/settings/ProfilePhotoUploader.tsx b/src/components/learners/settings/ProfilePhotoUploader.tsx
new file mode 100644
index 0000000..971d815
--- /dev/null
+++ b/src/components/learners/settings/ProfilePhotoUploader.tsx
@@ -0,0 +1,52 @@
+/*
+ * ======================================================================
+ * Copyright (C) 2025 - lzaycoe (Lazy Code)
+ * ======================================================================
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * ======================================================================
+ */
+import Image from 'next/image';
+
+export default function ProfilePhotoUploader() {
+ return (
+
+
+
+
+
+
+ Image size should be under 1MB and image ratio needs to be 1:1
+
+
+ );
+}
diff --git a/src/components/learners/settings/ProfileSettings.tsx b/src/components/learners/settings/ProfileSettings.tsx
new file mode 100644
index 0000000..b06e3ef
--- /dev/null
+++ b/src/components/learners/settings/ProfileSettings.tsx
@@ -0,0 +1,83 @@
+/*
+ * ======================================================================
+ * Copyright (C) 2025 - lzaycoe (Lazy Code)
+ * ======================================================================
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * ======================================================================
+ */
+'use client';
+
+import NavigationBar from '../../commons/learners/NavigationBar';
+import Profile from '../../commons/learners/Profile';
+import React from 'react';
+
+import PasswordChangeForm from './PasswordChangeForm';
+import ProfileForm from './ProfileForm';
+import ProfilePhotoUploader from './ProfilePhotoUploader';
+
+/*
+ * ======================================================================
+ * Copyright (C) 2025 - lzaycoe (Lazy Code)
+ * ======================================================================
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * ======================================================================
+ */
+
+export default function ProfileSettings() {
+ return (
+