From fe37c542b224128bc7f173712679cd7862245c38 Mon Sep 17 00:00:00 2001 From: betigirma Date: Mon, 31 Mar 2025 12:49:07 -0300 Subject: [PATCH 01/17] i added capacity-field in the form --- .../get-started/fields/capacity-field.tsx | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 components/shared/get-started/fields/capacity-field.tsx diff --git a/components/shared/get-started/fields/capacity-field.tsx b/components/shared/get-started/fields/capacity-field.tsx new file mode 100644 index 00000000..c5db3ab8 --- /dev/null +++ b/components/shared/get-started/fields/capacity-field.tsx @@ -0,0 +1,37 @@ +'use client'; + +import { + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from '@/components/ui/form'; +import { Input } from '@/components/ui/input'; +import type { AgeFieldProps } from '@/types/get-started'; + +export const CapacityField = ({ control, className }: AgeFieldProps) => { + return ( + ( + + Capacity + + { + const value = e.target.value; + field.onChange(value); + }} + /> + + + + )} + /> + ); +}; From adc7d547e2f0d128bcd05593aaf7c9fc6ac49cd9 Mon Sep 17 00:00:00 2001 From: betigirma Date: Mon, 31 Mar 2025 12:50:07 -0300 Subject: [PATCH 02/17] i changed specialization to expertise --- .../shared/get-started/fields/specialization-field.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/components/shared/get-started/fields/specialization-field.tsx b/components/shared/get-started/fields/specialization-field.tsx index 24eac87b..c6f7b795 100644 --- a/components/shared/get-started/fields/specialization-field.tsx +++ b/components/shared/get-started/fields/specialization-field.tsx @@ -6,12 +6,9 @@ import { FormLabel, } from '@/components/ui/form'; import { Checkbox } from '@/components/ui/checkbox'; -import { SpecializationFieldProps } from '@/types/get-started'; +import { ExpertiseFieldProps } from '@/types/get-started'; -export function SpecializationField({ - control, - options, -}: SpecializationFieldProps) { +export function SpecializationField({ control, options }: ExpertiseFieldProps) { return ( Date: Mon, 31 Mar 2025 12:51:12 -0300 Subject: [PATCH 03/17] i changed Gender to gender and defaultvalue to value --- components/shared/get-started/fields/gender-field.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/components/shared/get-started/fields/gender-field.tsx b/components/shared/get-started/fields/gender-field.tsx index 9a1c84b7..99281791 100644 --- a/components/shared/get-started/fields/gender-field.tsx +++ b/components/shared/get-started/fields/gender-field.tsx @@ -1,3 +1,5 @@ +'use client'; + import { FormField, FormItem, @@ -13,13 +15,13 @@ export function GenderField({ control, options, className }: GenderFieldProps) { return ( ( - + Gender From e1776cadbbe8d15e4e3f59596603daa2db336dc6 Mon Sep 17 00:00:00 2001 From: betigirma Date: Mon, 31 Mar 2025 12:53:33 -0300 Subject: [PATCH 04/17] here i added to send the form data to backend --- .../get-started/main/GetStartedMentorForm.tsx | 97 ++++++++++++++++--- 1 file changed, 82 insertions(+), 15 deletions(-) diff --git a/components/shared/get-started/main/GetStartedMentorForm.tsx b/components/shared/get-started/main/GetStartedMentorForm.tsx index d19c0e67..73211e14 100644 --- a/components/shared/get-started/main/GetStartedMentorForm.tsx +++ b/components/shared/get-started/main/GetStartedMentorForm.tsx @@ -1,8 +1,11 @@ 'use client'; import { useForm } from 'react-hook-form'; -import { getStartedMentorFormSchema } from '@/types/get-started'; -import { getStartedMentorFormValues } from '@/types/get-started'; +import { + getStartedMentorFormSchema, + type getStartedMentorFormValues, + type timeType, +} from '@/types/get-started'; import { zodResolver } from '@hookform/resolvers/zod'; import { Form } from '@/components/ui/form'; import { AgeField } from '../fields/age-field'; @@ -10,12 +13,47 @@ import { GenderField } from '../fields/gender-field'; import { getStartedForm } from '@/data/get-started-data'; import { LocationField } from '../fields/location-field'; import { SpecializationField } from '../fields/specialization-field'; -import { useEffect } from 'react'; +import { CapacityField } from '../fields/capacity-field'; +import { useEffect, useState } from 'react'; import { Button } from '@/components/ui/button'; import { useRouter } from 'next/navigation'; import { AvailabilityFields } from '../fields/availability/availability-fields'; +import { submitMentorForm } from '@/actions/admin/admin'; +import type { Account } from '@/types/users'; +import { userProfile } from '@/actions/auth/login'; +import { toast } from '@/hooks/use-toast'; + +interface GetStartedMentorFormProps { + initialUser?: Account; // Optional prop for SSR +} + +const GetStartedMentorForm = ({ initialUser }: GetStartedMentorFormProps) => { + const [loading, setLoading] = useState(false); + const [clientUser, setClientUser] = useState( + initialUser || null + ); + const router = useRouter(); + + useEffect(() => { + if (!initialUser) { + const fetchUserProfile = async () => { + try { + const userAccount = await userProfile(); + setClientUser(userAccount); + } catch (error) { + console.error('Failed to fetch user profile:', error); + } + }; + fetchUserProfile(); + } + }, [initialUser]); + + const defaultTime: timeType = { + hour: getStartedForm.hours[0].value, + minute: getStartedForm.minutes[0].value, + dayPeriod: getStartedForm.dayPeriods[0].value, + }; -const GetStartedMentorForm = () => { const form = useForm({ resolver: zodResolver(getStartedMentorFormSchema), mode: 'onChange', @@ -23,7 +61,8 @@ const GetStartedMentorForm = () => { age: 29, gender: 'male', location: '', - specialization: ['marriageCounseling'], + expertise: ['marriageCounseling'], + capacity: 5, availability: { monday: undefined, tuesday: undefined, @@ -36,16 +75,39 @@ const GetStartedMentorForm = () => { }, }); - const router = useRouter(); // Initialize the useRouter hook + const onSubmit = async (data: getStartedMentorFormValues) => { + if (!clientUser?.id) { + toast({ + variant: 'destructive', + title: 'Authentication Error', + description: 'Please sign in to submit the mentor form.', + }); + return; + } - const onSubmit = (data: getStartedMentorFormValues) => { - // Navigate to /mentor after form submission - router.push('/mentor'); // Use router.push for smooth navigation - }; + try { + setLoading(true); + await submitMentorForm(data, clientUser.id); - const { - formState: { errors }, - } = form; + toast({ + variant: 'success', + title: 'Profile Updated!', + description: 'Your mentor profile has been successfully updated.', + }); + + router.push('/mentor'); + } catch (error) { + console.error('Submission error:', error); + toast({ + variant: 'destructive', + title: 'Update Failed', + description: + 'There was an error updating your profile. Please try again.', + }); + } finally { + setLoading(false); + } + }; return (
@@ -65,9 +127,14 @@ const GetStartedMentorForm = () => { control={form.control} options={getStartedForm.specializationOptions} /> + - From c41c3ea4c38d8c2d9653558c9bac5bb83b2d381b Mon Sep 17 00:00:00 2001 From: betigirma Date: Mon, 31 Mar 2025 12:55:26 -0300 Subject: [PATCH 05/17] here i fetched the updated mentors information and added a toggle to change the status --- .../shared/admin/admin-mentors/mentors.tsx | 77 +++++++++++++++---- 1 file changed, 64 insertions(+), 13 deletions(-) diff --git a/components/shared/admin/admin-mentors/mentors.tsx b/components/shared/admin/admin-mentors/mentors.tsx index 1405829c..0f45f385 100644 --- a/components/shared/admin/admin-mentors/mentors.tsx +++ b/components/shared/admin/admin-mentors/mentors.tsx @@ -8,12 +8,16 @@ import type { Column, FilterOption } from '@/types/data-table'; import { toast } from '@/hooks/use-toast'; import { InviteMentorDialog } from './invite-mentor-dialog'; import { endPoints } from '@/data/end-points'; -import { deleteMentor } from '@/actions/admin/admin'; +import { deleteMentor, toggleMentorStatus } from '@/actions/admin/admin'; import type { Account } from '@/types/users'; import { userProfile } from '@/actions/auth/login'; import { Mentor } from '@/types/mentor'; +import { Switch } from '@/components/ui/switch'; -const columns: Column[] = [ +const createColumns = ( + client: Account | null, + setTriggerState: React.Dispatch> +): Column[] => [ { key: 'name', header: 'Name', @@ -30,41 +34,87 @@ const columns: Column[] = [ { key: 'age', header: 'Age', - render: (mentor: Mentor) => (mentor.age === null ? 'null' : mentor.age), + render: (mentor: Mentor) => (mentor.age === null ? 'N/A' : mentor.age), }, { key: 'gender', header: 'Gender' }, { key: 'expertise', header: 'Expertise', render: (mentor: Mentor) => - mentor.expertise === null ? 'null' : mentor.expertise, + mentor.expertise + ? Object.entries(mentor.expertise) + .map(([key, description]) => `${key}: ${description}`) + .join(', ') + : 'N/A', }, { key: 'availability', header: 'Availability', render: (mentor: Mentor) => - mentor.availability === null - ? 'null' - : mentor.availability?.startDate || 'null', + mentor.availability + ? Object.entries(mentor.availability) + .map(([day, times]) => `${day}: ${times.join(', ')}`) + .join('; ') + : 'N/A', + }, + { + key: 'capacity', + header: 'Capacity', + render: (mentor: Mentor) => + mentor.capacity === null ? 'N/A' : mentor.capacity, }, { key: 'location', header: 'Location', - render: (mentor: Mentor) => - mentor.location === null ? 'null' : mentor.location, + render: (mentor: Mentor) => (mentor.location ? mentor.location : 'N/A'), }, { key: 'isActive', header: 'Status', render: (mentor: Mentor) => ( - {mentor.isActive ? 'Yes' : 'No'} +
+ { + try { + if (!client?.id) { + throw new Error('User account ID missing'); + } + + await toggleMentorStatus(String(mentor.id), client.id, checked); + + mentor.isActive = checked; + setTriggerState((prev) => !prev); + + toast({ + variant: 'success', + title: 'Status Updated!', + description: `Mentor status has been ${checked ? 'activated' : 'deactivated'}.`, + }); + } catch (error) { + console.error('Status toggle error:', error); + toast({ + variant: 'destructive', + title: 'Error!', + description: + error instanceof Error + ? error.message + : 'Failed to update mentor status', + }); + } + }} + /> + + {mentor.isActive ? 'Active' : 'Inactive'} + +
), }, ]; const filterOptions: FilterOption[] = [ - { key: 'isActive', label: 'Yes' }, - { key: 'isActive', label: 'No' }, + { key: 'gender', label: 'FEMALE' }, + { key: 'gender', label: 'MALE' }, ]; const searchFields: (keyof Mentor)[] = ['name', 'email', 'gender', 'isActive']; @@ -81,6 +131,7 @@ const MentorsTable: React.FC = () => { }; fetchUserProfile(); }, []); + const endPoint = `${endPoints.adminMentors}?accountId=${clientUser?.id}`; const [itemsPerPage, onItemsPerPageChange] = useState(10); @@ -130,7 +181,7 @@ const MentorsTable: React.FC = () => { tag="admin-mentors" apiUrl={endPoint} - columns={columns} + columns={createColumns(clientUser, setTriggerState)} searchFields={searchFields} filterOptions={filterOptions} itemsPerPage={itemsPerPage} From ba12c81f410e75e3cae57ac9064f4cbf8440b43c Mon Sep 17 00:00:00 2001 From: betigirma Date: Mon, 31 Mar 2025 12:56:57 -0300 Subject: [PATCH 06/17] here i changed the putData() to patchData() in the PatchRequest --- base-api/method.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base-api/method.ts b/base-api/method.ts index 708233c4..0edab098 100644 --- a/base-api/method.ts +++ b/base-api/method.ts @@ -54,7 +54,7 @@ class PatchRequest extends ApiRequest { super(url, tag, data, 'PATCH'); } - public async putData() { + public async patchData() { return this.executeRequest(); } } From bacd82c2a6d4ff2102642484679a442de9a844ee Mon Sep 17 00:00:00 2001 From: betigirma Date: Mon, 31 Mar 2025 12:58:51 -0300 Subject: [PATCH 07/17] here i added an action to submitMentorForm and toggleMentorStatus --- actions/admin/admin.ts | 76 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 2 deletions(-) diff --git a/actions/admin/admin.ts b/actions/admin/admin.ts index 9a150702..80a9aebc 100644 --- a/actions/admin/admin.ts +++ b/actions/admin/admin.ts @@ -5,11 +5,14 @@ import { PostRequest, PatchRequest, } from '@/base-api/method'; -import { inviteMentorProps } from '@/types/requests'; +import type { inviteMentorProps } from '@/types/requests'; +import type { getStartedMentorFormValues } from '@/types/get-started'; + import { revalidateTag } from 'next/cache'; const Url = { adminAccount: `admin/account`, adminMentors: `admin/mentor`, + mentorProfile: `mentor/profile`, }; export const checkAccount = async (params: string) => { @@ -30,7 +33,7 @@ export const createOrganazation = async ( 'createOrg', body ); - const data = await putRequest.putData(); + const data = await putRequest.patchData(); return data; }; @@ -59,6 +62,75 @@ export const inviteMentore = async (body: inviteMentorProps) => { return data; }; +export const submitMentorForm = async ( + formData: getStartedMentorFormValues, + accountId: string +) => { + // Transform data to match backend format + const backendData = { + expertise: formData.expertise.reduce( + (acc, exp) => { + const expertiseMap: Record = { + marriageCounseling: 'Expert in marriage counseling', + discipleship: 'Expert in discipleship counseling', + spritual: 'Expert in spiritual counseling', + dayToDay: 'Expert in day-to-day counseling', + lifeCoach: 'Expert in life coaching', + psychology: 'Expert in psychological counseling', + }; + const key = + exp + .replace(/Counseling$/, 'Counselor') + .replace(/([A-Z])/g, ' $1') + .trim() + .toLowerCase() + 'Counselor'; + acc[key] = expertiseMap[exp] || `Expert in ${exp}`; + return acc; + }, + {} as Record + ), + capacity: formData.capacity, + availability: Object.entries(formData.availability) + .filter(([_, value]) => value !== undefined) + .reduce( + (acc, [day, value]) => { + if (!value) return acc; + + const formattedDay = day.charAt(0).toUpperCase() + day.slice(1); + const startTime = value.startTime; + const endTime = value.endTime; + const timeRange = `${startTime.hour}:${startTime.minute} ${startTime.dayPeriod} - ${endTime.hour}:${endTime.minute} ${endTime.dayPeriod}`; + + acc[formattedDay] = [timeRange]; + return acc; + }, + {} as Record + ), + age: formData.age, + gender: formData.gender.toUpperCase(), + location: formData.location, + }; + + const url = `${Url.mentorProfile}?accountId=${accountId}`; + + const patchRequest = new PatchRequest(url, 'submit-mentor-form', backendData); + return await patchRequest.patchData(); +}; + +export const toggleMentorStatus = async ( + mentorId: string | number, + accountId: string, + isActive: boolean +) => { + const url = `${Url.adminMentors}/${mentorId}/toggle-status?accountId=${accountId}`; + const patchRequest = new PatchRequest(url, 'toggle-mentor-status', { + isActive, + }); + const data = await patchRequest.patchData(); + revalidateTag('admin-mentors'); + return data; +}; + export async function revalidateWithLogging(tag: string) { return revalidateTag(tag); } From 7369d8754a8f465a47fdfb2b9ba9f17c3483a11b Mon Sep 17 00:00:00 2001 From: betigirma Date: Mon, 31 Mar 2025 13:01:06 -0300 Subject: [PATCH 08/17] i changed specialization to expertise and added capacity --- types/get-started.ts | 106 +++++++++++-------------------------------- 1 file changed, 27 insertions(+), 79 deletions(-) diff --git a/types/get-started.ts b/types/get-started.ts index 43b0d7ca..1ec91556 100644 --- a/types/get-started.ts +++ b/types/get-started.ts @@ -1,12 +1,13 @@ +import type React from 'react'; import { getStartedForm } from '@/data/get-started-data'; -import { Dispatch, SetStateAction } from 'react'; -import { UseFormReturn } from 'react-hook-form'; +import type { Dispatch, SetStateAction } from 'react'; +import type { UseFormReturn } from 'react-hook-form'; import { z } from 'zod'; const hourValues = getStartedForm.hours.map((hour) => hour.value) as [ string, ...string[], -]; // type assertion ensures that it is a tuple with atleast one string +]; const minuteValues = getStartedForm.minutes.map((minute) => minute.value) as [ string, ...string[], @@ -34,7 +35,7 @@ export type dailyAvailabilityType = z.infer; // the zod schema for the form One requirements export const getStartedMentorFormSchema = z.object({ age: z.preprocess( - (value) => (value === '' ? undefined : Number(value)), // changes the shadcn input which returns a string for the age to a number + (value) => (value === '' ? undefined : Number(value)), z .number() .min(9, { message: 'Age must be at least 9.' }) @@ -51,7 +52,8 @@ export const getStartedMentorFormSchema = z.object({ .max(30, { message: 'location must not be longer than 30 characters.', }), - specialization: z + + expertise: z .array( z.enum([ 'marriageCounseling', @@ -62,11 +64,18 @@ export const getStartedMentorFormSchema = z.object({ 'psychology', ]), { - // is an array that can have one or more of these fields - required_error: 'You need to select at least one specialization', + required_error: 'You need to select at least one expertise', } ) - .min(1, 'You need to select at least one specialization'), + .min(1, 'You need to select at least one expertise'), + + capacity: z.preprocess( + (value) => (value === '' ? undefined : Number(value)), + z + .number() + .min(1, { message: 'Capacity must be at least 1.' }) + .max(20, { message: 'Capacity must be no more than 20.' }) + ), availability: z.object({ monday: z.union([dailyAvailabilitySchema, z.undefined()]), tuesday: z.union([dailyAvailabilitySchema, z.undefined()]), @@ -77,52 +86,6 @@ export const getStartedMentorFormSchema = z.object({ sunday: z.union([dailyAvailabilitySchema, z.undefined()]), }), }); -// .refine( -// (data) => { -// const parseTime = (time: timeType) => { -// const hour = parseInt(time.hour, 10); -// const minute = parseInt(time.minute, 10); -// return (time.dayPeriod === "PM" ? (hour % 12) + 12 : hour % 12) * 60 + minute; -// }; - -// return Object.entries(data.availability).every(([day, times]) => { -// if (!times) return true; // Skip days with no availability -// const startTime = parseTime(times.startTime); -// const endTime = parseTime(times.endTime); -// return startTime < endTime; -// }); -// }, -// { -// message: "Start time must be earlier than end time for each day.", -// path: ["availability"], // Highlight the `availability` field in errors -// } -// ); -// .refine( -// (data) => { -// const parseTime = (hour: string, minute: string, period: string) => { -// const h = parseInt(hour, 10); -// const m = parseInt(minute, 10); -// return (period === "PM" ? (h % 12) + 12 : h % 12) * 60 + m; -// }; - -// const startTime = parseTime( -// data.startHour, -// data.startMinute, -// data.startDayPeriod -// ); -// const endTime = parseTime( -// data.endHour, -// data.endMinute, -// data.endDayPeriod -// ); - -// return startTime < endTime; -// }, -// { -// message: "", -// path: ["startHour"], // Attach to startHour or a relevant field -// } -// ); export type getStartedMentorFormValues = z.infer< typeof getStartedMentorFormSchema @@ -130,7 +93,6 @@ export type getStartedMentorFormValues = z.infer< export type availabilityType = z.infer; -// for the Availability popup in the mentor form export const MentorAvailabilityFormSchema = z.object({ availability: z.object({ monday: z.union([dailyAvailabilitySchema, z.undefined()]), @@ -142,26 +104,6 @@ export const MentorAvailabilityFormSchema = z.object({ sunday: z.union([dailyAvailabilitySchema, z.undefined()]), }), }); -// .refine( -// (data) => { -// const parseTime = (time: timeType) => { -// const hour = parseInt(time.hour, 10); -// const minute = parseInt(time.minute, 10); -// return (time.dayPeriod === "PM" ? (hour % 12) + 12 : hour % 12) * 60 + minute; -// }; - -// return Object.entries(data.availability).every(([day, times]) => { -// if (!times) return true; // Skip days with no availability -// const startTime = parseTime(times.startTime); -// const endTime = parseTime(times.endTime); -// return startTime < endTime; -// }); -// }, -// { -// message: "Start time must be earlier than end time for each day.", -// path: ["availability"], // Highlight the `availability` field in errors -// } -// ); export type MentorAvailabilityFormValues = z.infer< typeof MentorAvailabilityFormSchema @@ -173,7 +115,7 @@ export type AvailabilityType = z.infer< export const getStartedAdminFormSchema = z.object({ age: z.preprocess( - (value) => (value === '' ? undefined : Number(value)), // changes the shadcn input which returns a string for the age to a number + (value) => (value === '' ? undefined : Number(value)), z .number() .min(9, { message: 'Age must be at least 9.' }) @@ -193,9 +135,9 @@ export const getStartedAdminFormSchema = z.object({ phoneNumber: z.string().refine( (value) => { if (value.startsWith('+')) { - return value.length === 13 && /^\+\d{12}$/.test(value); // Starts with + and followed by 12 digits + return value.length === 13 && /^\+\d{12}$/.test(value); } else { - return value.length === 10 && /^\d{10}$/.test(value); // Exactly 10 digits with no + + return value.length === 10 && /^\d{10}$/.test(value); } }, { @@ -208,16 +150,22 @@ export type getStartedAdminFormValues = z.infer< typeof getStartedAdminFormSchema >; +// Update interface props to use expertise instead of specialization export interface AgeFieldProps { control: any; className?: string; } -export interface SpecializationFieldProps { +export interface ExpertiseFieldProps { control: any; options: { label: string; value: string }[]; } +export interface CapacityFieldProps { + control: any; + className?: string; +} + export interface LocationFieldProps { control: any; } From ec937ae720d8e35263d722d217440f821dc3ed33 Mon Sep 17 00:00:00 2001 From: betigirma Date: Mon, 31 Mar 2025 13:03:17 -0300 Subject: [PATCH 09/17] change expertise type to json and added capacity --- types/mentor.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/types/mentor.ts b/types/mentor.ts index 0ec77065..ed535c04 100644 --- a/types/mentor.ts +++ b/types/mentor.ts @@ -1,17 +1,17 @@ import { colors } from '@/components/shared/Mentor/Info'; -import { Account } from './users'; +//import { Account } from './users'; -// types/mentor.ts export interface Mentor { id: string | number; accountId: string; name: string; email: string; - expertise?: string | null; + expertise?: { [key: string]: string } | null; age?: number | null; gender: string; location?: string | null; - availability?: { startDate: string } | null; + availability?: { [key: string]: string[] } | null; + capacity?: number | null; isActive: boolean; createdAt: string; updatedAt: string; From a01cd09cd58aa605056a0bd45a5f78c82718b5db Mon Sep 17 00:00:00 2001 From: betigirma Date: Mon, 31 Mar 2025 13:05:00 -0300 Subject: [PATCH 10/17] GetStartedMentorFormValues added --- types/requests/index.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/types/requests/index.ts b/types/requests/index.ts index 05ef8789..c645aca2 100644 --- a/types/requests/index.ts +++ b/types/requests/index.ts @@ -20,3 +20,20 @@ export interface inviteMentorProps { name: string; email: string; } + +export interface GetStartedMentorFormValues { + age: number; + gender: 'male' | 'female'; + location: string; + capacity: number; + specialization: string[]; + availability: { + monday?: string; + tuesday?: string; + wednesday?: string; + thursday?: string; + friday?: string; + saturday?: string; + sunday?: string; + }; +} From 7d59464c96131b76939a5ffbd48dcd4ad77eb4c5 Mon Sep 17 00:00:00 2001 From: betigirma Date: Mon, 31 Mar 2025 13:08:21 -0300 Subject: [PATCH 11/17] fix some build errors --- components/shared/data-table.tsx | 14 +---- package-lock.json | 90 ++++++++++++++++---------------- 2 files changed, 46 insertions(+), 58 deletions(-) diff --git a/components/shared/data-table.tsx b/components/shared/data-table.tsx index 2ee8a3e8..187c9437 100644 --- a/components/shared/data-table.tsx +++ b/components/shared/data-table.tsx @@ -33,8 +33,6 @@ import { DropdownMenuTrigger, } from '@radix-ui/react-dropdown-menu'; -// ... other imports - export interface Column { key: keyof T; header: string; @@ -99,7 +97,7 @@ const DataTable = ({ if (response && response.data) { setData(response.data); - setTotalPages(response.meta.totalPages); // Use meta.totalPages for pagination + setTotalPages(response.meta.totalPages); } else { throw new Error('Invalid response format'); } @@ -120,14 +118,11 @@ const DataTable = ({ const handleSearchChange = (event: React.ChangeEvent) => { setSearchTerm(event.target.value); }; - // Apply search and filters to the data const filteredData = data.filter((item) => { - // Apply search const matchesSearch = searchFields.some((field) => item[field]?.toString().toLowerCase().includes(searchTerm.toLowerCase()) ); - // Apply filters const matchesFilters = filters.every((filter) => { const [key, value] = filter.split(':'); return item[key as keyof T]?.toString() === value; @@ -136,13 +131,6 @@ const DataTable = ({ return matchesSearch && matchesFilters; }); - // Filter data based on search term - // const filteredData = data.filter((item) => - // searchFields.some((field) => - // item[field]?.toString().toLowerCase().includes(searchTerm.toLowerCase()) - // ) - // ); - const handleDelete = (id: string | number) => { setDeleteDialog({ open: true, id }); }; diff --git a/package-lock.json b/package-lock.json index 79eb1e9f..1295ee9b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -89,9 +89,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.26.0.tgz", - "integrity": "sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==", + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", + "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" @@ -808,9 +808,9 @@ } }, "node_modules/@next/env": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.1.7.tgz", - "integrity": "sha512-d9jnRrkuOH7Mhi+LHav2XW91HOgTAWHxjMPkXMGBc9B2b7614P7kjt8tAplRvJpbSt4nbO1lugcT/kAaWzjlLQ==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.2.4.tgz", + "integrity": "sha512-+SFtMgoiYP3WoSswuNmxJOCwi06TdWE733D+WPjpXIe4LXGULwEaofiiAy6kbS0+XjM5xF5n3lKuBwN2SnqD9g==", "license": "MIT" }, "node_modules/@next/eslint-plugin-next": { @@ -824,9 +824,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.1.7.tgz", - "integrity": "sha512-hPFwzPJDpA8FGj7IKV3Yf1web3oz2YsR8du4amKw8d+jAOHfYHYFpMkoF6vgSY4W6vB29RtZEklK9ayinGiCmQ==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.2.4.tgz", + "integrity": "sha512-1AnMfs655ipJEDC/FHkSr0r3lXBgpqKo4K1kiwfUf3iE68rDFXZ1TtHdMvf7D0hMItgDZ7Vuq3JgNMbt/+3bYw==", "cpu": [ "arm64" ], @@ -840,9 +840,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.1.7.tgz", - "integrity": "sha512-2qoas+fO3OQKkU0PBUfwTiw/EYpN+kdAx62cePRyY1LqKtP09Vp5UcUntfZYajop5fDFTjSxCHfZVRxzi+9FYQ==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.2.4.tgz", + "integrity": "sha512-3qK2zb5EwCwxnO2HeO+TRqCubeI/NgCe+kL5dTJlPldV/uwCnUgC7VbEzgmxbfrkbjehL4H9BPztWOEtsoMwew==", "cpu": [ "x64" ], @@ -856,9 +856,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.1.7.tgz", - "integrity": "sha512-sKLLwDX709mPdzxMnRIXLIT9zaX2w0GUlkLYQnKGoXeWUhcvpCrK+yevcwCJPdTdxZEUA0mOXGLdPsGkudGdnA==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.2.4.tgz", + "integrity": "sha512-HFN6GKUcrTWvem8AZN7tT95zPb0GUGv9v0d0iyuTb303vbXkkbHDp/DxufB04jNVD+IN9yHy7y/6Mqq0h0YVaQ==", "cpu": [ "arm64" ], @@ -872,9 +872,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.1.7.tgz", - "integrity": "sha512-zblK1OQbQWdC8fxdX4fpsHDw+VSpBPGEUX4PhSE9hkaWPrWoeIJn+baX53vbsbDRaDKd7bBNcXRovY1hEhFd7w==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.2.4.tgz", + "integrity": "sha512-Oioa0SORWLwi35/kVB8aCk5Uq+5/ZIumMK1kJV+jSdazFm2NzPDztsefzdmzzpx5oGCJ6FkUC7vkaUseNTStNA==", "cpu": [ "arm64" ], @@ -888,9 +888,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.1.7.tgz", - "integrity": "sha512-GOzXutxuLvLHFDAPsMP2zDBMl1vfUHHpdNpFGhxu90jEzH6nNIgmtw/s1MDwpTOiM+MT5V8+I1hmVFeAUhkbgQ==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.2.4.tgz", + "integrity": "sha512-yb5WTRaHdkgOqFOZiu6rHV1fAEK0flVpaIN2HB6kxHVSy/dIajWbThS7qON3W9/SNOH2JWkVCyulgGYekMePuw==", "cpu": [ "x64" ], @@ -904,9 +904,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.1.7.tgz", - "integrity": "sha512-WrZ7jBhR7ATW1z5iEQ0ZJfE2twCNSXbpCSaAunF3BKcVeHFADSI/AW1y5Xt3DzTqPF1FzQlwQTewqetAABhZRQ==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.2.4.tgz", + "integrity": "sha512-Dcdv/ix6srhkM25fgXiyOieFUkz+fOYkHlydWCtB0xMST6X9XYI3yPDKBZt1xuhOytONsIFJFB08xXYsxUwJLw==", "cpu": [ "x64" ], @@ -920,9 +920,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.1.7.tgz", - "integrity": "sha512-LDnj1f3OVbou1BqvvXVqouJZKcwq++mV2F+oFHptToZtScIEnhNRJAhJzqAtTE2dB31qDYL45xJwrc+bLeKM2Q==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.2.4.tgz", + "integrity": "sha512-dW0i7eukvDxtIhCYkMrZNQfNicPDExt2jPb9AZPpL7cfyUo7QSNl1DjsHjmmKp6qNAqUESyT8YFl/Aw91cNJJg==", "cpu": [ "arm64" ], @@ -936,9 +936,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.1.7.tgz", - "integrity": "sha512-dC01f1quuf97viOfW05/K8XYv2iuBgAxJZl7mbCKEjMgdQl5JjAKJ0D2qMKZCgPWDeFbFT0Q0nYWwytEW0DWTQ==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.2.4.tgz", + "integrity": "sha512-SbnWkJmkS7Xl3kre8SdMF6F/XDh1DTFEhp0jRTj/uB8iPKoU2bb2NDfcu+iifv1+mxQEd1g2vvSxcZbXSKyWiQ==", "cpu": [ "x64" ], @@ -5534,9 +5534,9 @@ } }, "node_modules/axios": { - "version": "1.7.8", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.8.tgz", - "integrity": "sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==", + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz", + "integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -8739,12 +8739,12 @@ } }, "node_modules/next": { - "version": "15.1.7", - "resolved": "https://registry.npmjs.org/next/-/next-15.1.7.tgz", - "integrity": "sha512-GNeINPGS9c6OZKCvKypbL8GTsT5GhWPp4DM0fzkXJuXMilOO2EeFxuAY6JZbtk6XIl6Ws10ag3xRINDjSO5+wg==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/next/-/next-15.2.4.tgz", + "integrity": "sha512-VwL+LAaPSxEkd3lU2xWbgEOtrM8oedmyhBqaVNmgKB+GvZlCy9rgaEc+y2on0wv+l0oSFqLtYD6dcC1eAedUaQ==", "license": "MIT", "dependencies": { - "@next/env": "15.1.7", + "@next/env": "15.2.4", "@swc/counter": "0.1.3", "@swc/helpers": "0.5.15", "busboy": "1.6.0", @@ -8759,14 +8759,14 @@ "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "15.1.7", - "@next/swc-darwin-x64": "15.1.7", - "@next/swc-linux-arm64-gnu": "15.1.7", - "@next/swc-linux-arm64-musl": "15.1.7", - "@next/swc-linux-x64-gnu": "15.1.7", - "@next/swc-linux-x64-musl": "15.1.7", - "@next/swc-win32-arm64-msvc": "15.1.7", - "@next/swc-win32-x64-msvc": "15.1.7", + "@next/swc-darwin-arm64": "15.2.4", + "@next/swc-darwin-x64": "15.2.4", + "@next/swc-linux-arm64-gnu": "15.2.4", + "@next/swc-linux-arm64-musl": "15.2.4", + "@next/swc-linux-x64-gnu": "15.2.4", + "@next/swc-linux-x64-musl": "15.2.4", + "@next/swc-win32-arm64-msvc": "15.2.4", + "@next/swc-win32-x64-msvc": "15.2.4", "sharp": "^0.33.5" }, "peerDependencies": { From d69b7c51ad23d33258975faee40d9ccb93fa26b4 Mon Sep 17 00:00:00 2001 From: betigirma Date: Mon, 14 Apr 2025 08:18:11 -0300 Subject: [PATCH 12/17] here is both the PatchRequest and PutRequest in the method. --- base-api/method.ts | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/base-api/method.ts b/base-api/method.ts index 0edab098..9b14e3fe 100644 --- a/base-api/method.ts +++ b/base-api/method.ts @@ -48,7 +48,7 @@ class PostRequest extends ApiRequest { } } -// PUT request subclass +// PATCH request subclass class PatchRequest extends ApiRequest { constructor(url: string, tag: string, data: unknown) { super(url, tag, data, 'PATCH'); @@ -59,6 +59,17 @@ class PatchRequest extends ApiRequest { } } +// PUT request subclass +class PutRequest extends ApiRequest { + constructor(url: string, tag: string, data: unknown) { + super(url, tag, data, 'PUT'); + } + + public async putData() { + return this.executeRequest(); + } +} + // DELETE request subclass class DeleteRequest extends ApiRequest { constructor(url: string, tag: string) { @@ -70,4 +81,4 @@ class DeleteRequest extends ApiRequest { } } -export { GetRequest, PostRequest, PatchRequest, DeleteRequest }; +export { GetRequest, PostRequest, PatchRequest, PutRequest, DeleteRequest }; From 57e40631a6c1f018327046d3767f9ced56ff6d18 Mon Sep 17 00:00:00 2001 From: betigirma Date: Mon, 14 Apr 2025 08:32:26 -0300 Subject: [PATCH 13/17] I move mentor/admin API types to type folders. --- actions/admin/admin.ts | 24 ++++++++++-------------- types/admin.ts | 6 ++++++ types/mentor.ts | 7 +++++++ 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/actions/admin/admin.ts b/actions/admin/admin.ts index 80a9aebc..4167db76 100644 --- a/actions/admin/admin.ts +++ b/actions/admin/admin.ts @@ -7,6 +7,8 @@ import { } from '@/base-api/method'; import type { inviteMentorProps } from '@/types/requests'; import type { getStartedMentorFormValues } from '@/types/get-started'; +import { ToggleMentorStatusProps } from '@/types/mentor'; +import { CreateOrganizationProps } from '@/types/admin'; import { revalidateTag } from 'next/cache'; const Url = { @@ -24,17 +26,13 @@ export const checkAccount = async (params: string) => { return data; }; -export const createOrganazation = async ( - id: string, - body: { name: string; domain: string } -) => { +export const createOrganazation = async ({ id, body }: CreateOrganizationProps) => { const putRequest = new PatchRequest( `${Url.adminAccount}/${id}`, 'createOrg', body ); - const data = await putRequest.patchData(); - return data; + return await putRequest.patchData(); }; export const deleteMentor = async (id: string) => { @@ -117,15 +115,13 @@ export const submitMentorForm = async ( return await patchRequest.patchData(); }; -export const toggleMentorStatus = async ( - mentorId: string | number, - accountId: string, - isActive: boolean -) => { +export const toggleMentorStatus = async ({ + mentorId, + accountId, + isActive, +}: ToggleMentorStatusProps) => { const url = `${Url.adminMentors}/${mentorId}/toggle-status?accountId=${accountId}`; - const patchRequest = new PatchRequest(url, 'toggle-mentor-status', { - isActive, - }); + const patchRequest = new PatchRequest(url, 'toggle-mentor-status', { isActive }); const data = await patchRequest.patchData(); revalidateTag('admin-mentors'); return data; diff --git a/types/admin.ts b/types/admin.ts index 01029d68..8155da88 100644 --- a/types/admin.ts +++ b/types/admin.ts @@ -12,3 +12,9 @@ export interface Admin { status: string; profileImage: string; } + +export interface CreateOrganizationProps { + id: string; + body: { name: string; domain: string }; +} + diff --git a/types/mentor.ts b/types/mentor.ts index ed535c04..9f9bfcf2 100644 --- a/types/mentor.ts +++ b/types/mentor.ts @@ -17,6 +17,13 @@ export interface Mentor { updatedAt: string; } +export interface ToggleMentorStatusProps { + mentorId: string | number; + accountId: string; + isActive: boolean; +} + + export type User = { id: string; name: string; From a2130a80fd926f8c27faec3eafcec82e031d25f8 Mon Sep 17 00:00:00 2001 From: betigirma Date: Mon, 14 Apr 2025 08:41:37 -0300 Subject: [PATCH 14/17] the endpoint was changed in backend. --- actions/admin/admin.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/actions/admin/admin.ts b/actions/admin/admin.ts index 4167db76..bc3ed8f9 100644 --- a/actions/admin/admin.ts +++ b/actions/admin/admin.ts @@ -15,6 +15,7 @@ const Url = { adminAccount: `admin/account`, adminMentors: `admin/mentor`, mentorProfile: `mentor/profile`, + inviteAdmin: `admin/user`, }; export const checkAccount = async (params: string) => { @@ -120,7 +121,7 @@ export const toggleMentorStatus = async ({ accountId, isActive, }: ToggleMentorStatusProps) => { - const url = `${Url.adminMentors}/${mentorId}/toggle-status?accountId=${accountId}`; + const url = `${Url.inviteAdmin}/${mentorId}/activate/${accountId}`; const patchRequest = new PatchRequest(url, 'toggle-mentor-status', { isActive }); const data = await patchRequest.patchData(); revalidateTag('admin-mentors'); From 6cb73b32be14926166ebf2f3edcc734fbdf36861 Mon Sep 17 00:00:00 2001 From: betigirma Date: Mon, 14 Apr 2025 08:55:15 -0300 Subject: [PATCH 15/17] ensure consistent single-argument object usage --- actions/admin/admin.ts | 9 +++++++-- components/shared/admin/admin-mentors/mentors.tsx | 6 +++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/actions/admin/admin.ts b/actions/admin/admin.ts index bc3ed8f9..0ce4f11e 100644 --- a/actions/admin/admin.ts +++ b/actions/admin/admin.ts @@ -27,7 +27,10 @@ export const checkAccount = async (params: string) => { return data; }; -export const createOrganazation = async ({ id, body }: CreateOrganizationProps) => { +export const createOrganazation = async ({ + id, + body, +}: CreateOrganizationProps) => { const putRequest = new PatchRequest( `${Url.adminAccount}/${id}`, 'createOrg', @@ -122,7 +125,9 @@ export const toggleMentorStatus = async ({ isActive, }: ToggleMentorStatusProps) => { const url = `${Url.inviteAdmin}/${mentorId}/activate/${accountId}`; - const patchRequest = new PatchRequest(url, 'toggle-mentor-status', { isActive }); + const patchRequest = new PatchRequest(url, 'toggle-mentor-status', { + isActive, + }); const data = await patchRequest.patchData(); revalidateTag('admin-mentors'); return data; diff --git a/components/shared/admin/admin-mentors/mentors.tsx b/components/shared/admin/admin-mentors/mentors.tsx index 0f45f385..a3bf294a 100644 --- a/components/shared/admin/admin-mentors/mentors.tsx +++ b/components/shared/admin/admin-mentors/mentors.tsx @@ -81,7 +81,11 @@ const createColumns = ( throw new Error('User account ID missing'); } - await toggleMentorStatus(String(mentor.id), client.id, checked); + await toggleMentorStatus({ + mentorId: String(mentor.id), + accountId: client.id, + isActive: checked, + }); mentor.isActive = checked; setTriggerState((prev) => !prev); From f93fa3f3c965f5e35a016308b14235fb60170103 Mon Sep 17 00:00:00 2001 From: betigirma Date: Mon, 14 Apr 2025 08:59:29 -0300 Subject: [PATCH 16/17] align createOrganazation call with updated props format --- components/views/admin/create-org.tsx | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/components/views/admin/create-org.tsx b/components/views/admin/create-org.tsx index 95018c9e..bc79599a 100644 --- a/components/views/admin/create-org.tsx +++ b/components/views/admin/create-org.tsx @@ -68,10 +68,11 @@ const CreateOrgView = () => { domain: orgData.companyDomain as string, }; - const response = await createOrganazation( - clientUser?.id as string, - reqBody - ); + const response = await createOrganazation({ + id: clientUser?.id as string, + body: reqBody, + }); + if (response) { toast({ variant: 'success', From 5e77a190b804b437726c2a6f3412040d016c2705 Mon Sep 17 00:00:00 2001 From: betigirma Date: Mon, 14 Apr 2025 09:01:16 -0300 Subject: [PATCH 17/17] fix build errors. --- components/views/admin/create-org.tsx | 2 +- types/admin.ts | 1 - types/mentor.ts | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/components/views/admin/create-org.tsx b/components/views/admin/create-org.tsx index bc79599a..9adbbb3c 100644 --- a/components/views/admin/create-org.tsx +++ b/components/views/admin/create-org.tsx @@ -72,7 +72,7 @@ const CreateOrgView = () => { id: clientUser?.id as string, body: reqBody, }); - + if (response) { toast({ variant: 'success', diff --git a/types/admin.ts b/types/admin.ts index 8155da88..385f906c 100644 --- a/types/admin.ts +++ b/types/admin.ts @@ -17,4 +17,3 @@ export interface CreateOrganizationProps { id: string; body: { name: string; domain: string }; } - diff --git a/types/mentor.ts b/types/mentor.ts index 9f9bfcf2..51192b45 100644 --- a/types/mentor.ts +++ b/types/mentor.ts @@ -23,7 +23,6 @@ export interface ToggleMentorStatusProps { isActive: boolean; } - export type User = { id: string; name: string;