From 19485f92dfe7762383f24e63c516aac7261d304f Mon Sep 17 00:00:00 2001 From: Said mia Date: Mon, 25 Nov 2024 23:53:11 +0100 Subject: [PATCH] update system auth with permissions and complete integrations --- .../renderer/src/components/EditProfile.tsx | 84 +++--- .../renderer/src/components/EditeSettings.tsx | 58 ++++ .../src/renderer/src/components/Sidebar.tsx | 51 ++-- .../renderer/src/components/UsersTable.tsx | 4 - .../components/formations/users-columns.tsx | 272 +++++++++--------- .../src/components/navbar/profile.tsx | 9 +- .../organization/Organization-columns.tsx | 30 +- .../src/renderer/src/components/ui/toast.tsx | 1 + .../renderer/src/containers/Registration.tsx | 14 - .../src/renderer/src/containers/Setting.tsx | 66 ++--- .../src/renderer/src/containers/profile.tsx | 19 +- .../renderer/src/containers/users-listing.tsx | 61 ++-- .../src/renderer/src/data/sidebar-items.ts | 43 ++- .../src/hooks/api/organization/create-org.ts | 20 +- .../api/organization/get-all-organizations.ts | 2 +- .../api/organization/get-organization-data.ts | 24 +- .../organization/get-organization-users.ts | 35 +++ .../src/hooks/api/organization/update-org.ts | 7 + .../src/renderer/src/hooks/api/user/me.ts | 48 ++++ .../src/hooks/api/user/useUpdateUser.ts | 48 ++++ .../src/hooks/editForms/useHandleEditOrg.ts | 7 +- .../editForms/useHandleEditRegAndOwner.ts | 31 +- apps/desk/src/renderer/src/hooks/useAuth.ts | 53 ++-- .../renderer/src/hooks/useGetCachedData.ts | 16 ++ .../renderer/src/hooks/useRegistrations.ts | 61 ++-- .../renderer/src/permissions/HasPermission.ts | 34 ++- .../renderer/src/providers/react-query.tsx | 69 ++++- .../desk/src/renderer/src/providers/toast.tsx | 1 - .../renderer/src/store/slices/auth.slice.ts | 43 ++- .../renderer/src/utils/schemas/formSchema.ts | 36 +-- .../signup/components/PersonalInfosForm.tsx | 163 ++++++----- apps/web/src/app/signup/page.tsx | 1 + apps/web/src/hooks/useSignUp.ts | 3 +- apps/web/src/lib/toasts.ts | 57 ---- 34 files changed, 884 insertions(+), 587 deletions(-) create mode 100644 apps/desk/src/renderer/src/components/EditeSettings.tsx create mode 100644 apps/desk/src/renderer/src/hooks/api/organization/get-organization-users.ts create mode 100644 apps/desk/src/renderer/src/hooks/api/user/me.ts create mode 100644 apps/desk/src/renderer/src/hooks/api/user/useUpdateUser.ts create mode 100644 apps/desk/src/renderer/src/hooks/useGetCachedData.ts delete mode 100644 apps/desk/src/renderer/src/providers/toast.tsx delete mode 100644 apps/web/src/lib/toasts.ts diff --git a/apps/desk/src/renderer/src/components/EditProfile.tsx b/apps/desk/src/renderer/src/components/EditProfile.tsx index ff9bc553..5536cfa9 100644 --- a/apps/desk/src/renderer/src/components/EditProfile.tsx +++ b/apps/desk/src/renderer/src/components/EditProfile.tsx @@ -1,26 +1,58 @@ -import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; -import { Avatar, AvatarImage, AvatarFallback } from './ui/avatar'; -import { Button } from './ui/button'; -import { Label } from './ui/label'; -import { Input } from './ui/input'; -import { useTranslate } from '@renderer/hooks/useTranslate'; import Profile_Img from '@renderer/assets/images/profile_img.png'; +import { User } from '@renderer/hooks/api/user/me'; +import useUpdateUser from '@renderer/hooks/api/user/useUpdateUser'; +import { useTranslate } from '@renderer/hooks/useTranslate'; import { EditProfileSchema } from '@renderer/utils/schemas/formSchema'; +import { UploadIcon } from 'lucide-react'; +import { useMemo } from 'react'; +import { useForm } from 'react-hook-form'; +import { Avatar, AvatarFallback, AvatarImage } from './ui/avatar'; +import { Button } from './ui/button'; +import { Input } from './ui/input'; +import { Label } from './ui/label'; + +//TODO: USE REUSABLE FORM FIELDS COMPOONENT @PAPOCHA + +export default function EditProfile({ data }: { data: User }): JSX.Element { -export default function EditProfile(): JSX.Element { const { t, isRtl } = useTranslate(); + const mutation = useUpdateUser(); + + const defaultValues = useMemo(() => { + return { + firstName: data?.firstName ?? '', + lastName: data?.lastName ?? '', + email: data?.email ?? '', + id: data?.id ?? '', + }; + }, [data]); + const { register, handleSubmit, formState: { errors }, } = useForm({ resolver: zodResolver(EditProfileSchema), + defaultValues: { + firstName: defaultValues?.firstName ?? '', + lastName: defaultValues?.lastName ?? '', + email: defaultValues?.email ?? '', + }, }); const onSubmit = (data: any) => { - console.log('Form Data:', data); + mutation.mutate({ + userId: defaultValues?.id ?? '', + data: { + firstName: defaultValues.firstName === data.firstName ? undefined : data.firstName, + lastName: defaultValues.lastName === data.lastName ? undefined : data.lastName, + email: defaultValues.email === data.email ? undefined : data.email, + //TODO: add phone + // phone: data.phone + }, + }); }; return ( @@ -108,7 +140,7 @@ export default function EditProfile(): JSX.Element {

)} -
+ {/*
+
*/} {/* Footer Buttons */}
-
); -} - -function UploadIcon(props): JSX.Element { - return ( - - - - - - ); -} +} \ No newline at end of file diff --git a/apps/desk/src/renderer/src/components/EditeSettings.tsx b/apps/desk/src/renderer/src/components/EditeSettings.tsx new file mode 100644 index 00000000..f08dd621 --- /dev/null +++ b/apps/desk/src/renderer/src/components/EditeSettings.tsx @@ -0,0 +1,58 @@ +import useRegistrations from '@renderer/hooks/useRegistrations'; +import { useTranslate } from '@renderer/hooks/useTranslate'; +import { Card, CardContent, CardHeader } from './ui/card'; +import { OrganizationFormData } from '@renderer/utils/schemas/formSchema'; +import FormInputItem from './ui/form-input-item'; +import { registrationFields } from '@renderer/data/organinzation-fields-input'; +import { Button } from './ui/button'; +import { FaSpinner } from 'react-icons/fa'; +import { OrganizationsData } from '@renderer/hooks/api/organization/get-all-organizations'; + +export default function EditeSettings({ data }: { data: OrganizationsData }) { + const { methods, isPending, handleSubmit, defaultValues } = + useRegistrations(data); + const { t } = useTranslate(); + + return ( +
+

+ {t('registration.EditOrganization')} +

+
+ + + {t('registration.title')} + + +
+ {registrationFields.map((field) => ( + + ))} +
+
+
+ +
+
+ ); +} diff --git a/apps/desk/src/renderer/src/components/Sidebar.tsx b/apps/desk/src/renderer/src/components/Sidebar.tsx index e54ce6d8..77dd2d53 100644 --- a/apps/desk/src/renderer/src/components/Sidebar.tsx +++ b/apps/desk/src/renderer/src/components/Sidebar.tsx @@ -1,15 +1,20 @@ -import { useEffect, useState } from 'react'; -import { useTranslation } from 'react-i18next'; -import { Link } from '@tanstack/react-router'; import { navItems } from '@renderer/data/sidebar-items'; +import { useAppSelector } from '@renderer/store/hooks'; +import { Link } from '@tanstack/react-router'; +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; export default function Sidebar() { const [active, setActive] = useState('home'); const { t } = useTranslation(); - useEffect(() => { - // Example: Handle any required logic on mount - }, []); + const { isAccountActivated, userRole, userProfile } = useAppSelector( + (state) => ({ + isAccountActivated: state.auth.auth.isAccountActivated, + userRole: state.auth.auth.role, + userProfile: state.auth.auth.userType, + }) + ); return (
@@ -20,22 +25,24 @@ export default function Sidebar() { {t('sidebar.sections.dashboard')}
{/* Others Section */} diff --git a/apps/desk/src/renderer/src/components/UsersTable.tsx b/apps/desk/src/renderer/src/components/UsersTable.tsx index 1ecb73bf..330e7aa4 100644 --- a/apps/desk/src/renderer/src/components/UsersTable.tsx +++ b/apps/desk/src/renderer/src/components/UsersTable.tsx @@ -8,16 +8,12 @@ import EditUsers from './formations/edit-users'; export interface UsersProps { data: Users[]; } -// type UserRollType = 'admin' | 'user' | 'owner'; export default function UsersTable ({data} : {data: Users[]}) { const [component, setComponent] = useState('table'); const [defaultValue, setdefaultValue] = useState(null); - // const - - const { isRtl } = useTranslate(); return ( diff --git a/apps/desk/src/renderer/src/components/formations/users-columns.tsx b/apps/desk/src/renderer/src/components/formations/users-columns.tsx index 4900c65f..4ade9689 100644 --- a/apps/desk/src/renderer/src/components/formations/users-columns.tsx +++ b/apps/desk/src/renderer/src/components/formations/users-columns.tsx @@ -1,141 +1,145 @@ -import { ColumnDef } from "@tanstack/react-table" -import { Checkbox } from "../ui/checkbox" -import DeleteModal from "../DeleteModal" -import { Button } from "../ui/button" -import { useTranslate } from "@renderer/hooks/useTranslate" -import SortHeader from "../costum-data/sort-header" -import ButtonsAction from "../organization/org-table-actions" +import { ColumnDef } from '@tanstack/react-table'; +import SortHeader from '../costum-data/sort-header'; +import DeleteModal from '../DeleteModal'; +import ButtonsAction from '../organization/org-table-actions'; +import { Checkbox } from '../ui/checkbox'; -import RedirectButton from "../redirectButton" -import CostumSelect from "../costum-select" +import CostumSelect from '../costum-select'; +import RedirectButton from '../redirectButton'; export interface Users { - id: string - firstName: string - lastName: string - phone: string - email: string - // role select + id: string; + firstName: string; + lastName: string; + phone: string; + email: string; + // role select } - - -export const usersColumns = (setRowData: (rowData: Users) => void +export const usersColumns = ( + setRowData: (rowData: Users) => void ): ColumnDef[] => { + return [ + { + accessorKey: 'id', + header: ({ table }) => ( +
+ + table.toggleAllPageRowsSelected(!!value) + } + aria-label="Select all" + /> - return [ - { - accessorKey: 'id', - header: ({ table }) => ( -
- table.toggleAllPageRowsSelected(!!value)} - aria-label="Select all" - /> - - {table.getIsSomeRowsSelected() && ( - { }} - /> - )} -
- ), - cell: ({ row }) => ( -
- row.toggleSelected(!!value)} - aria-label="Select row" - key="checkbox" - /> -

{row.index + 1}

-
- ), - }, - { - accessorKey: 'firstName', - header: ({ column }) => { - return ( - column.clearSorting()} - OnClick={() => column.toggleSorting(column.getIsSorted() === 'asc')} - label={('themesTable.firstName')} - /> - ); - }, - cell: ({ row }) =>

{row.original.firstName}

- }, - { - accessorKey: 'lastName', - header: ({ column }) => { - return ( - column.clearSorting()} - OnClick={() => column.toggleSorting(column.getIsSorted() === 'asc')} - label={('themesTable.lastName')} - /> - ); - }, - cell: ({ row }) =>

{row.original.lastName}

- }, - { - accessorKey: 'email', - header: ({ column }) => { - return ( - column.clearSorting()} - OnClick={() => column.toggleSorting(column.getIsSorted() === 'asc')} - label={('themesTable.email')} - /> - ); - }, - cell: ({ row }) =>

{row.original.email}

- }, - { - accessorKey: 'phone', - header: 'themesTable.phone', - cell: ({ row }) =>

{row.original.phone}

- }, - { - accessorKey: 'permissions', - header: ('themesTable.permission'), - cell: () => ( - { console.log("view permissions") }} text="themesTable.permission" /> - // - ), - }, - { - accessorKey: 'role', - header: ('themesTable.role'), - cell: () => ( - - ), - }, - { - accessorKey: 'options', - header: ('themesTable.options'), - cell: ({ row }) => ( - - ), - }, - - ] -} \ No newline at end of file + {table.getIsSomeRowsSelected() && ( + {}} + /> + )} +
+ ), + cell: ({ row }) => ( +
+ row.toggleSelected(!!value)} + aria-label="Select row" + key="checkbox" + /> +

{row.index + 1}

+
+ ), + }, + { + accessorKey: 'firstName', + header: ({ column }) => { + return ( + column.clearSorting()} + OnClick={() => column.toggleSorting(column.getIsSorted() === 'asc')} + label={'themesTable.firstName'} + /> + ); + }, + cell: ({ row }) => ( +

{row.original.firstName}

+ ), + }, + { + accessorKey: 'lastName', + header: ({ column }) => { + return ( + column.clearSorting()} + OnClick={() => column.toggleSorting(column.getIsSorted() === 'asc')} + label={'themesTable.lastName'} + /> + ); + }, + cell: ({ row }) => ( +

{row.original.lastName}

+ ), + }, + { + accessorKey: 'email', + header: ({ column }) => { + return ( + column.clearSorting()} + OnClick={() => column.toggleSorting(column.getIsSorted() === 'asc')} + label={'themesTable.email'} + /> + ); + }, + cell: ({ row }) =>

{row.original.email}

, + }, + { + accessorKey: 'phone', + header: 'themesTable.phone', + cell: ({ row }) =>

{row.original.phone}

, + }, + { + accessorKey: 'permissions', + header: 'themesTable.permission', + cell: () => ( + { + console.log('view permissions'); + }} + text="themesTable.permission" + /> + // + ), + }, + { + accessorKey: 'role', + header: 'themesTable.role', + cell: () => , + }, + { + accessorKey: 'options', + header: 'themesTable.options', + cell: ({ row }) => ( + + ), + }, + ]; +}; diff --git a/apps/desk/src/renderer/src/components/navbar/profile.tsx b/apps/desk/src/renderer/src/components/navbar/profile.tsx index d2943657..14103ecd 100644 --- a/apps/desk/src/renderer/src/components/navbar/profile.tsx +++ b/apps/desk/src/renderer/src/components/navbar/profile.tsx @@ -2,8 +2,10 @@ import { FaUserCircle } from 'react-icons/fa'; import { FiLogOut } from 'react-icons/fi'; import { HiOutlineChevronDown } from 'react-icons/hi'; import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover'; +import { useRouter } from '@tanstack/react-router'; export default function ProfilePopover() { + const router = useRouter(); return ( @@ -17,8 +19,11 @@ export default function ProfilePopover() {

Sygafor Admin

-
diff --git a/apps/desk/src/renderer/src/components/organization/Organization-columns.tsx b/apps/desk/src/renderer/src/components/organization/Organization-columns.tsx index 5ca93aad..444ff376 100644 --- a/apps/desk/src/renderer/src/components/organization/Organization-columns.tsx +++ b/apps/desk/src/renderer/src/components/organization/Organization-columns.tsx @@ -8,7 +8,6 @@ import DeleteModal from '../DeleteModal'; import RedirectButton from '../redirectButton'; -// rs -- ice. -- cnss -- address - logo export type Organization = { id: string; logo: string; @@ -34,14 +33,16 @@ export const Columns = (
table.toggleAllPageRowsSelected(!!value)} + onCheckedChange={(value) => + table.toggleAllPageRowsSelected(!!value) + } aria-label="Select all" /> {table.getIsSomeRowsSelected() && ( { }} + onDelete={() => {}} /> )}
@@ -76,29 +77,30 @@ export const Columns = ( header: 'organization.rs', cell: ({ row }) =>

{row.getValue('rs')}

, }, + { + accessorKey: 'address', + header: 'organization.address', + cell: ({ row }) => ( +

{row.getValue('address')}

+ ), + }, { accessorKey: 'cnss', header: 'organization.cnss', - cell: ({ row }) =>

{row.getValue('cnss')}

, + cell: ({ row }) => ( +

{row.getValue('cnss')}

+ ), }, { accessorKey: 'ice', header: 'ice', - cell: ({ row }) => ( -

{row.getValue('ice')}

- ), + cell: ({ row }) =>

{row.getValue('ice')}

, }, { accessorKey: 'viewUsers', header: 'organization.viewUsers', cell: () => ( - // ), }, @@ -115,7 +117,7 @@ export const Columns = ( ); }, cell: ({ row }) => ( - { }} value={row.getValue('enabled')} /> + {}} value={row.getValue('enabled')} /> ), }, { diff --git a/apps/desk/src/renderer/src/components/ui/toast.tsx b/apps/desk/src/renderer/src/components/ui/toast.tsx index c7bb4df8..b8871400 100644 --- a/apps/desk/src/renderer/src/components/ui/toast.tsx +++ b/apps/desk/src/renderer/src/components/ui/toast.tsx @@ -107,6 +107,7 @@ const ToastDescription = React.forwardRef< {...props} /> )); + ToastDescription.displayName = ToastPrimitives.Description.displayName; type ToastProps = React.ComponentPropsWithoutRef; diff --git a/apps/desk/src/renderer/src/containers/Registration.tsx b/apps/desk/src/renderer/src/containers/Registration.tsx index 31d33686..181488f0 100644 --- a/apps/desk/src/renderer/src/containers/Registration.tsx +++ b/apps/desk/src/renderer/src/containers/Registration.tsx @@ -1,12 +1,9 @@ import { Button } from '@renderer/components/ui/button'; import { Card, CardContent, CardHeader } from '@renderer/components/ui/card'; import FormInputItem from '@renderer/components/ui/form-input-item'; -import { usersFields } from '@renderer/data/formation-fields-input'; import { registrationFields, userFields } from '@renderer/data/organinzation-fields-input'; import withAuth from '@renderer/hoc/with-auth'; import useHandleEditRegAndOwner from '@renderer/hooks/editForms/useHandleEditRegAndOwner'; -import useHandleEditUser from '@renderer/hooks/editForms/useHandleEditUser'; -import useRegistrations from '@renderer/hooks/useRegistrations'; import { useTranslate } from '@renderer/hooks/useTranslate'; import { OrganizationFormData, UserFormData } from '@renderer/utils/schemas/formSchema'; import React from 'react'; @@ -16,16 +13,6 @@ const Registration: React.FC = () => { const { t } = useTranslate(); // get members , form provider method, and submit handler const { methods: methods1, isPending, handleSubmit } = useHandleEditRegAndOwner(); - // const { methods: methods2, isPending: isPending1, handleSubmit: handleSubmit1 } = useHandleEditUser( - // { - // id: '', - // firstName: 'HAMZA', - // lastName: 'AMEUR', - // email: 'SYGAR@gmail.com', - // phone: '123456789' - // }, 'edit' - // ); - return (
@@ -37,7 +24,6 @@ const Registration: React.FC = () => { > - {t('registration.title')} diff --git a/apps/desk/src/renderer/src/containers/Setting.tsx b/apps/desk/src/renderer/src/containers/Setting.tsx index 2908d3e7..395658e0 100644 --- a/apps/desk/src/renderer/src/containers/Setting.tsx +++ b/apps/desk/src/renderer/src/containers/Setting.tsx @@ -1,55 +1,27 @@ -import { Button } from "@renderer/components/ui/button"; -import { Card, CardContent, CardHeader } from "@renderer/components/ui/card"; -import FormInputItem from "@renderer/components/ui/form-input-item"; -import { registrationFields } from "@renderer/data/organinzation-fields-input"; -import useRegistrations from "@renderer/hooks/useRegistrations"; -import { useTranslate } from "@renderer/hooks/useTranslate"; -import { OrganizationFormData } from "@renderer/utils/schemas/formSchema"; -import { FaSpinner } from "react-icons/fa"; +import EditeSettings from '@renderer/components/EditeSettings'; +import { useOrganizationData } from '@renderer/hooks/api/organization/get-organization-data'; +import { useAppSelector } from '@renderer/store/hooks'; +import { FaSpinner } from 'react-icons/fa'; const SettingPage = (): JSX.Element => { - const { t } = useTranslate(); - const { methods, isPending, handleSubmit } = useRegistrations(); + const orgId = useAppSelector((state) => state.auth.auth.organizationId); + const { data, isSuccess, isLoading } = useOrganizationData(orgId); + + if (isLoading) { + return ( +
+ +
+ ); + } + + if (isSuccess) { + return ; + } return ( -
-

- {t('registration.EditOrganization')} -

-
- - - {t('registration.title')} - - -
- {registrationFields.map((field) => ( - - ))} -
-
-
- -
-
+
Error loading organization data
); }; diff --git a/apps/desk/src/renderer/src/containers/profile.tsx b/apps/desk/src/renderer/src/containers/profile.tsx index 05519a10..57e06f7a 100644 --- a/apps/desk/src/renderer/src/containers/profile.tsx +++ b/apps/desk/src/renderer/src/containers/profile.tsx @@ -1,9 +1,26 @@ import EditProfile from '@renderer/components/EditProfile'; +import { useGetMe } from '@renderer/hooks/api/user/me'; const ProfilePage = (): JSX.Element => { + const { data, isLoading, isError, error, isSuccess, refetch } = useGetMe(); + + if (isLoading) { + return ( +
+ Loading... +
+ ); + } + + if (isError) { + return ( +
Error loading organization data
+ ); + } + return (
- +
); }; diff --git a/apps/desk/src/renderer/src/containers/users-listing.tsx b/apps/desk/src/renderer/src/containers/users-listing.tsx index 24e6fdd8..d8463309 100644 --- a/apps/desk/src/renderer/src/containers/users-listing.tsx +++ b/apps/desk/src/renderer/src/containers/users-listing.tsx @@ -1,30 +1,43 @@ import UsersTable from '@renderer/components/UsersTable'; import withAuth from '@renderer/hoc/with-auth'; -import { mockUsers } from '@renderer/utils/static/organizations'; - +import { useOrganizationUsers } from '@renderer/hooks/api/organization/get-organization-users'; +import { useAppSelector } from '@renderer/store/hooks'; const usersListing = () => { - // const { data, isSuccess, isLoading, isError } = useGetAllUsers(); + const orgId = useAppSelector((state) => state.auth.auth.organizationId); + + const { data, isLoading, isError, error, isSuccess, refetch } = + useOrganizationUsers(orgId); + + console.log(data); + if (isLoading) { + return ( +
+ Loading... +
+ ); + } + + if (isError) { + return ( +
Error loading organization data
+ ); + } - // if (isLoading) { - // return ( - //
- // Loading... - //
- // ); - // } - - // if (isError) { - // return ( - //
Error loading organization data
- // ); - // } - - // if (isSuccess) { - // return ; - // } - - return ; -} + if (isSuccess) { + return ( + ({ + id: user.id, + firstName: user.firstName, + lastName: user.lastName, + email: user.email, + phone: user.phone, + // role: user.role, + }))} + /> + ); + } +}; -export default withAuth(usersListing) \ No newline at end of file +export default withAuth(usersListing); diff --git a/apps/desk/src/renderer/src/data/sidebar-items.ts b/apps/desk/src/renderer/src/data/sidebar-items.ts index 01f05901..7e60a888 100644 --- a/apps/desk/src/renderer/src/data/sidebar-items.ts +++ b/apps/desk/src/renderer/src/data/sidebar-items.ts @@ -6,39 +6,76 @@ import { UsersIcon, IdentificationIcon, } from '@heroicons/react/24/outline'; -import { FaUsers } from "react-icons/fa"; +import { hasPermission } from '@renderer/permissions/HasPermission'; +import { Role, UserType } from '@renderer/store/slices/auth.slice'; +import { FaUsers } from 'react-icons/fa'; -export const navItems = [ - { name: 'home', label: 'sidebar.items.home', href: '/dashboard', icon: HomeIcon }, +export const navItems = ( + isAccountActivated: boolean, + userRole: Role, + userProfile: UserType +) => [ + { + name: 'home', + label: 'sidebar.items.home', + href: '/dashboard', + icon: HomeIcon, + canVue: true, + }, { name: 'registration', label: 'sidebar.items.registration', href: '/registration', icon: IdentificationIcon, + canVue: hasPermission( + isAccountActivated, + userRole, + userProfile + ).canAccessRegistration().canRead, }, { name: 'organizations', label: 'sidebar.items.organizations', href: '/organizations', icon: UsersIcon, + canVue: hasPermission( + isAccountActivated, + userRole, + userProfile + ).AccessOrganizations().canRead, }, { name: 'settings', label: 'sidebar.items.settings', href: '/settings', icon: Cog6ToothIcon, + canVue: hasPermission( + isAccountActivated, + userRole, + userProfile + ).canAccessSettings(), }, { name: 'themes', label: 'sidebar.items.theme', href: '/themes-listing', icon: BellIcon, + canVue: hasPermission( + isAccountActivated, + userRole, + userProfile + ).AccessThemes().canRead, }, { name: 'users', label: 'sidebar.items.users', href: '/users-listing', icon: FaUsers, + canVue: hasPermission( + isAccountActivated, + userRole, + userProfile + ).canAccessUsers().canRead, }, // Add more items as needed ]; diff --git a/apps/desk/src/renderer/src/hooks/api/organization/create-org.ts b/apps/desk/src/renderer/src/hooks/api/organization/create-org.ts index c4bba821..af543a4d 100644 --- a/apps/desk/src/renderer/src/hooks/api/organization/create-org.ts +++ b/apps/desk/src/renderer/src/hooks/api/organization/create-org.ts @@ -3,10 +3,24 @@ import { api } from '@renderer/utils/api'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useToast } from '../../useToast'; -export interface CreateOrganParams { +type AddParticipant = { cnss: string; + imageLink?: string; + identity: string; + identityType: string; + firstName: string; + lastName: string; + email: string; + phone: string; +}; + +export interface CreateOrganParams { name: string; - freeTrial: number; + cnss: string; + imageLink?: string; + address: string; + ice: string; + owner: AddParticipant; } export default function useCreateOrg() { @@ -20,7 +34,7 @@ export default function useCreateOrg() { mutationKey: ['createOrg'], mutationFn: (params: CreateOrganParams) => - api.post('/organization/create', params, { + api.post('/organizations', params, { headers: { Authorization: `Bearer ${token}`, }, diff --git a/apps/desk/src/renderer/src/hooks/api/organization/get-all-organizations.ts b/apps/desk/src/renderer/src/hooks/api/organization/get-all-organizations.ts index b3a53b17..a461fd81 100644 --- a/apps/desk/src/renderer/src/hooks/api/organization/get-all-organizations.ts +++ b/apps/desk/src/renderer/src/hooks/api/organization/get-all-organizations.ts @@ -23,7 +23,7 @@ export const useGetAllOrganizations = () => { Authorization: `Bearer ${token}`, }, }), - staleTime: 0, + staleTime: Infinity, refetchOnMount: false, refetchOnWindowFocus: false, refetchOnReconnect: false, diff --git a/apps/desk/src/renderer/src/hooks/api/organization/get-organization-data.ts b/apps/desk/src/renderer/src/hooks/api/organization/get-organization-data.ts index 3e3d1547..20eab95f 100644 --- a/apps/desk/src/renderer/src/hooks/api/organization/get-organization-data.ts +++ b/apps/desk/src/renderer/src/hooks/api/organization/get-organization-data.ts @@ -4,25 +4,21 @@ import { useQuery } from '@tanstack/react-query'; import { OrganizationsData } from './get-all-organizations'; //TODO: use api Library to get the organization data -export const useOrganizationData = (organizationCnss: string | null) => { +export const useOrganizationData = (orgId:string) => { const token = useAppSelector((state) => state.auth.auth.token); - const { data, isLoading, isError, error,isSuccess, refetch } = useQuery({ - queryKey: ['organizationData', organizationCnss], - queryFn: () => api.get(`organization/get?cnss=${organizationCnss}`,{ - headers: { - Authorization: `Bearer ${token}`, - } - }), - refetchOnMount: false, - refetchOnWindowFocus: false, - refetchOnReconnect: false, - refetchInterval: false, - refetchIntervalInBackground: false, + const { data, isLoading, isError, error, isSuccess, refetch } = useQuery({ + queryKey: ['organizationData', orgId], + queryFn: () => + api.get(`organizations/${orgId}`, { + headers: { + Authorization: `Bearer ${token}`, + }, + }), }); return { - data: data?.data.organization as OrganizationsData, + data: data?.data as OrganizationsData, isLoading, isError, error, diff --git a/apps/desk/src/renderer/src/hooks/api/organization/get-organization-users.ts b/apps/desk/src/renderer/src/hooks/api/organization/get-organization-users.ts new file mode 100644 index 00000000..939002cd --- /dev/null +++ b/apps/desk/src/renderer/src/hooks/api/organization/get-organization-users.ts @@ -0,0 +1,35 @@ +import { useAppSelector } from '@renderer/store/hooks'; +import { api } from '@renderer/utils/api'; +import { useQuery } from '@tanstack/react-query'; +import { User } from '../user/me'; + +type OrgUsersType = { + page: number; + totalAmount: number; + totalPage: number; + users: User[]; +} + +//TODO: use api Library to get the organization data +export const useOrganizationUsers = (orgId: string) => { + const token = useAppSelector((state) => state.auth.auth.token); + + const { data, isLoading, isError, error, isSuccess, refetch } = useQuery({ + queryKey: ['organizationUsers', orgId], + queryFn: () => + api.get(`organizations/${orgId}/users`, { + headers: { + Authorization: `Bearer ${token}`, + }, + }), + }); + + return { + data: data?.data as OrgUsersType, + isLoading, + isError, + error, + isSuccess, + refetch, + }; +}; diff --git a/apps/desk/src/renderer/src/hooks/api/organization/update-org.ts b/apps/desk/src/renderer/src/hooks/api/organization/update-org.ts index ea8e8849..4d441372 100644 --- a/apps/desk/src/renderer/src/hooks/api/organization/update-org.ts +++ b/apps/desk/src/renderer/src/hooks/api/organization/update-org.ts @@ -7,6 +7,7 @@ import { } from '@tanstack/react-query'; import { OrganizationsData } from './get-all-organizations'; import { AxiosResponse } from 'axios'; +import { useToast } from '@renderer/hooks/useToast'; export interface UpdateOrganParams { orgId: string; @@ -24,6 +25,8 @@ export default function useUpdateOrg( const queryClient = useQueryClient(); + const { toast } = useToast(); + return useMutation({ mutationKey: ['UpdateOrg'], @@ -40,6 +43,10 @@ export default function useUpdateOrg( queryKey: ['organizationsData'], exact: true, }); + toast({ + title: 'success', + description: 'Organization updated successfully', + }); } catch (error) { console.log(error); } diff --git a/apps/desk/src/renderer/src/hooks/api/user/me.ts b/apps/desk/src/renderer/src/hooks/api/user/me.ts new file mode 100644 index 00000000..aea4a24e --- /dev/null +++ b/apps/desk/src/renderer/src/hooks/api/user/me.ts @@ -0,0 +1,48 @@ +import { useAppSelector } from '@renderer/store/hooks'; +import { api } from '@renderer/utils/api'; +import { useQuery } from '@tanstack/react-query'; + +export type User = { + id: string; + email: string; + phone: string; + cnss: number; + firstName: string; + lastName: string; + passwordChangedAt: string; + resetToken: string | null; + resetTokenExpiresAt: string | null; + role: string; + type: string; + identityType: string; + identity: string; + isActive: boolean; + organizationId: string; + updatedAt: string; + createdAt: string; +}; + +//TODO: use api Library to get the organization data +export const useGetMe = () => { + const token = useAppSelector((state) => state.auth.auth.token); + + const { data, isLoading, isError, error, status, isSuccess, refetch } = useQuery({ + queryKey: ['fetch-user-data', token], + queryFn: () => + api.get(`auth/me`, { + headers: { + Authorization: `Bearer ${token}`, + }, + }), + }); + + return { + data: data?.data as User, + isLoading, + isError, + error, + status, + isSuccess, + refetch, + }; +}; diff --git a/apps/desk/src/renderer/src/hooks/api/user/useUpdateUser.ts b/apps/desk/src/renderer/src/hooks/api/user/useUpdateUser.ts new file mode 100644 index 00000000..8704887e --- /dev/null +++ b/apps/desk/src/renderer/src/hooks/api/user/useUpdateUser.ts @@ -0,0 +1,48 @@ +import { useToast } from '@renderer/hooks/useToast'; +import { useAppSelector } from '@renderer/store/hooks'; +import { api } from '@renderer/utils/api'; +import { useMutation, UseMutationOptions } from '@tanstack/react-query'; +import { AxiosResponse } from 'axios'; + +export interface UpdateUserParams { + userId: string; + data: Partial<{ + firstName: string; + lastName: string; + email: string; + phone: string; + }>; +} + +export default function useUpdateUser( + options?: UseMutationOptions, Error, UpdateUserParams> +) { + const token = useAppSelector((state) => state.auth.auth.token); + const { toast } = useToast(); + + return useMutation({ + mutationKey: ['UpdateUser'], + + mutationFn: ({ userId, data }: UpdateUserParams) => + api.put(`user/${userId}`, data, { + headers: { + Authorization: `Bearer ${token}`, + }, + }), + + onSuccess: () => { + toast({ + title: 'success', + description: 'user chenges successfully', + }); + }, + ...options, + + onError: () => { + toast({ + title: 'error', + description: 'Error while changing data', + }); + }, + }); +} diff --git a/apps/desk/src/renderer/src/hooks/editForms/useHandleEditOrg.ts b/apps/desk/src/renderer/src/hooks/editForms/useHandleEditOrg.ts index dbb7fc4a..6fa4e019 100644 --- a/apps/desk/src/renderer/src/hooks/editForms/useHandleEditOrg.ts +++ b/apps/desk/src/renderer/src/hooks/editForms/useHandleEditOrg.ts @@ -31,7 +31,10 @@ export default function useHandelEditOrgs( updateMutation.mutate({ orgId: defaultValues.id, data: { - name: data.rs, + name: defaultValues.rs !== data.rs ? data.rs : undefined, + cnss: defaultValues.cnss !== data.cnss ? data.cnss : undefined, + address: defaultValues.address !== data.address ? data.address : undefined, + ice: defaultValues.ice !== data.ice ? data.ice : undefined, }, }); } @@ -42,7 +45,7 @@ export default function useHandelEditOrgs( const { id, enabled, logo, ...values } = defaultValues; const { logo: imageData, ...defaultData } = data; console.log('Data:', data); - console.log('Default Values:', values); + console.log('Default Values:', values); return JSON.stringify(defaultData) !== JSON.stringify(values); } }; diff --git a/apps/desk/src/renderer/src/hooks/editForms/useHandleEditRegAndOwner.ts b/apps/desk/src/renderer/src/hooks/editForms/useHandleEditRegAndOwner.ts index 0b77424b..27d08b95 100644 --- a/apps/desk/src/renderer/src/hooks/editForms/useHandleEditRegAndOwner.ts +++ b/apps/desk/src/renderer/src/hooks/editForms/useHandleEditRegAndOwner.ts @@ -20,26 +20,25 @@ export default function useHandleEditRegAndOwner() { ), }); - // const userMethods = useForm({ - // resolver: zodResolver(userSchema), - // defaultValues: useMemo( - // () => ({ - // // default values - // }), - // [] - // ), - // }); - const createMuation = useCreateOrg(); const handleSubmit = (data: OrganizationFormData & UserFormData) => { - // Handle form submission console.log('ikhan: ', data); - // createMuation.mutate({ - // name: data.rs, - // cnss: data.cnss, - // freeTrial: 30, - // }); + createMuation.mutate({ + name: data.rs, + cnss: data.cnss, + address: data.address, + ice: data.ice, + owner: { + cnss: data.userCnss, + identity: data.identity, + identityType: data.identityType, + firstName: data.firstName, + lastName: data.lastName, + email: data.email, + phone: data.phone, + } + }); }; return { diff --git a/apps/desk/src/renderer/src/hooks/useAuth.ts b/apps/desk/src/renderer/src/hooks/useAuth.ts index 50cc6ac9..99fde56a 100644 --- a/apps/desk/src/renderer/src/hooks/useAuth.ts +++ b/apps/desk/src/renderer/src/hooks/useAuth.ts @@ -1,8 +1,8 @@ import { useAppDispatch, useAppSelector } from '@renderer/store/hooks'; -import { setIsAuth } from '@renderer/store/slices/auth.slice'; +import { Role, setIsAuth, setUserData, UserType } from '@renderer/store/slices/auth.slice'; import { useRouter } from '@tanstack/react-router'; import { useCallback, useEffect, useMemo } from 'react'; -import { useQuery } from '@tanstack/react-query'; +import { useGetMe, User } from './api/user/me'; interface AuthState { isLoading: boolean; @@ -10,63 +10,52 @@ interface AuthState { isAuth: boolean; } -const fetchUser = async (token: string | null) => { - return new Promise((res, rej) => { - setTimeout(() => { - if (!token) rej('ba3osha'); - res('ok'); - }, 1000); - }); -}; - export const useAuth = (): AuthState => { const dispatch = useAppDispatch(); const { - auth: { isAuth, token }, + auth: { isAuth }, } = useAppSelector((state) => state.auth); // Select authentication state const router = useRouter(); + + const { error, isLoading, status, data } = useGetMe(); - const onSuccess = useCallback(() => { + const onSuccess = useCallback((usrData: User) => { dispatch(setIsAuth(true)); + dispatch(setUserData({ + userId: usrData.id ?? '', + organizationId: usrData.organizationId ?? '', + role: (usrData.role ?? 'User') as Role, + userType: (usrData.type ?? 'ORGANIZATION_USER') as UserType, + isAccountActivated: usrData.isActive, + })); + if (router.latestLocation.pathname === '/signin') { router.navigate({ to: '/' }); } }, [dispatch, router.latestLocation.pathname]); const onError = useCallback(() => { + dispatch(setIsAuth(false)); router.navigate({ to: '/signin' }); }, [router]); - const fetchUserCallback = useCallback( - () => fetchUser(token), - [fetchUser, token] - ); - - const { error, isLoading, status, refetch } = useQuery({ - queryKey: ['fetch-user-data', token], - enabled: !isAuth, - queryFn: fetchUserCallback, - refetchOnMount: false, - refetchOnWindowFocus: false, - }); - // TODO : refactor this @smia useEffect(() => { if (status === 'error') { onError(); } if (status === 'success') { - onSuccess(); + onSuccess(data); } }, [status]); - useEffect(() => { - if (token) { - refetch(); - } - }, [token]); + // useEffect(() => { + // if (token) { + // refetch(); + // } + // }, [token]); return useMemo( () => ({ diff --git a/apps/desk/src/renderer/src/hooks/useGetCachedData.ts b/apps/desk/src/renderer/src/hooks/useGetCachedData.ts new file mode 100644 index 00000000..6ce8fc56 --- /dev/null +++ b/apps/desk/src/renderer/src/hooks/useGetCachedData.ts @@ -0,0 +1,16 @@ +import { QueryKey, useQueryClient } from '@tanstack/react-query'; + +interface QueryResponse { + data: T; + [key: string]: any; +} + +export default function useGetCachedData(key: QueryKey): T | undefined { + const queryClient = useQueryClient(); + + const cachedData = queryClient.getQueryData>(key); + + console.log('cachedData', cachedData); + + return cachedData?.data; +} diff --git a/apps/desk/src/renderer/src/hooks/useRegistrations.ts b/apps/desk/src/renderer/src/hooks/useRegistrations.ts index e4d851af..01a352d8 100644 --- a/apps/desk/src/renderer/src/hooks/useRegistrations.ts +++ b/apps/desk/src/renderer/src/hooks/useRegistrations.ts @@ -1,52 +1,47 @@ import { zodResolver } from '@hookform/resolvers/zod'; +import { useAppSelector } from '@renderer/store/hooks'; import { OrganizationFormData, organizationSchema, - UserFormData, - userSchema, } from '@renderer/utils/schemas/formSchema'; -import { useMemo } from 'react'; import { useForm } from 'react-hook-form'; -import useCreateOrg from './api/organization/create-org'; +import { OrganizationsData } from './api/organization/get-all-organizations'; +import useUpdateOrg from './api/organization/update-org'; -export default function useRegistrations() { +export default function useRegistrations(data: OrganizationsData) { + const orgId = useAppSelector((state) => state.auth.auth.organizationId); + const defaultValues = { + rs: data.name, + cnss: data.cnss, + address: data.address, + ice: data.ice, + }; const methods = useForm({ resolver: zodResolver(organizationSchema), - defaultValues: useMemo( - () => ({ - // default values - }), - [] - ), }); - // const userMethods = useForm({ - // resolver: zodResolver(userSchema), - // defaultValues: useMemo( - // () => ({ - // // default values - // }), - // [] - // ), - // }); - - const createMuation = useCreateOrg(); - + const updateMutation = useUpdateOrg(); const handleSubmit = (data: OrganizationFormData) => { - // Handle form submission - console.log('ikhan: ', data); - // createMuation.mutate({ - // name: data.rs, - // cnss: data.cnss, - // freeTrial: 30, - // }); + if (defaultValues) { + updateMutation.mutate({ + orgId, + data: { + name: defaultValues.rs !== data.rs ? data.rs : undefined, + cnss: defaultValues.cnss !== data.cnss ? data.cnss : undefined, + address: + defaultValues.address !== data.address ? data.address : undefined, + ice: defaultValues.ice !== data.ice ? data.ice : undefined, + }, + }); + } }; return { methods, - isSuccess: createMuation.isSuccess, - isError: createMuation.isError, - isPending: createMuation.isPending, + isSuccess: updateMutation.isSuccess, + isError: updateMutation.isError, + isPending: updateMutation.isPending, + defaultValues, handleSubmit, }; } diff --git a/apps/desk/src/renderer/src/permissions/HasPermission.ts b/apps/desk/src/renderer/src/permissions/HasPermission.ts index 18367bf4..1872ea9e 100644 --- a/apps/desk/src/renderer/src/permissions/HasPermission.ts +++ b/apps/desk/src/renderer/src/permissions/HasPermission.ts @@ -1,26 +1,26 @@ -export type UserRoleType = 'admin' | 'user' | 'owner'; - -export type UserProfileType = 'SYGAR' | 'ORGANIZATION'; +import { Role, UserType } from "@renderer/store/slices/auth.slice"; export const hasPermission = ( isAccountActivated: boolean, - userRole: UserRoleType, - userProfile: UserProfileType + userRole: Role, + userProfile: UserType ) => { return { - // only SYGAR admin and owner can access registration + // only SOLUTION_OWNER admin and owner can access registration canAccessRegistration: () => ({ canRead: - isAccountActivated && userProfile === 'SYGAR' && userRole !== 'user', + isAccountActivated, canCUD: - isAccountActivated && userProfile === 'SYGAR' && userRole !== 'user', + isAccountActivated && + userProfile === 'SOLUTION_OWNER' && + userRole !== 'User', }), - // only SYGAR admin and owner can access organizations list + // only SOLUTION_OWNER admin and owner can access organizations list AccessOrganizations: () => { return { - canRead: isAccountActivated || userProfile === 'SYGAR', - canCUD: userProfile === 'SYGAR', + canRead: isAccountActivated, + canCUD: isAccountActivated && userProfile === 'SOLUTION_OWNER', }; }, @@ -33,17 +33,15 @@ export const hasPermission = ( canRead: isAccountActivated, canCUD: isAccountActivated && - userProfile === 'ORGANIZATION' && - (userRole !== 'user'), + userProfile === 'ORGANIZATION_USER' && + userRole !== 'User', }; }, - // only Activated Account and (SYGAR admin and owner) and (ORGANIZATION owner admin) + // only Activated Account and (SOLUTION_OWNER admin and owner) and (ORGANIZATION owner admin) canAccessUsers: () => ({ - canRead: - isAccountActivated && (userRole !== 'user'), - canCRUD: - isAccountActivated && (userRole !== 'user'), + canRead: isAccountActivated && userRole !== 'User', + canCRUD: isAccountActivated && userRole !== 'User', }), }; }; diff --git a/apps/desk/src/renderer/src/providers/react-query.tsx b/apps/desk/src/renderer/src/providers/react-query.tsx index cd5feddf..31019465 100644 --- a/apps/desk/src/renderer/src/providers/react-query.tsx +++ b/apps/desk/src/renderer/src/providers/react-query.tsx @@ -1,9 +1,70 @@ -import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { AnyAction } from '@reduxjs/toolkit'; +import { useToast } from '@renderer/hooks/useToast'; +import { useAppDispatch } from '@renderer/store/hooks'; +import { resetAuth } from '@renderer/store/slices/auth.slice'; +import { + MutationCache, + QueryCache, + QueryClient, + QueryClientProvider, +} from '@tanstack/react-query'; +import { AxiosError } from 'axios'; +import { Dispatch } from 'react'; + +// Define a reusable function for handling Unauthorized errors +function handleAxiosError( + error: unknown, + dispatch: Dispatch, + toast: (args: { title: string; description: string }) => void +) { + const axiosError = error as AxiosError; + const data = axiosError.response?.data as any; + + // Handle Unauthorized error + if (data && data.statusCode === 401 && data.error === 'Unauthorized') { + dispatch(resetAuth()); + localStorage.clear(); + toast({ + title: 'Unauthorized', + description: 'Your session has expired. Please log in again.', + }); + } + + // Handle Permissions + if (data && data.statusCode === 403 && data.message === 'Forbidden') { + toast({ + title: 'Forbidden', + description: + 'You do not have the required permissions to perform this action.', + }); + } +} -const queryClient = new QueryClient({ - defaultOptions: { queries: { retry: 0 } }, -}); export const ReactQueryProvider = ({ children }) => { + const dispatch = useAppDispatch(); + const { toast } = useToast(); + + const queryClient = new QueryClient({ + // Configure default options for queries + defaultOptions: { + queries: { + staleTime: Infinity, // Prevents automatic refetching + retry: false, // Prevent retries on failure + refetchOnWindowFocus: false, // Prevent refetch on window focus + refetchOnReconnect: false, // Prevent refetch on network reconnect + refetchOnMount: false, // Prevent automatic refetch when the component mounts + }, + }, + // Configure default options for mutations cache + mutationCache: new MutationCache({ + onError: (error) => handleAxiosError(error, dispatch, toast), + }), + // Configure default options for queries cache + queryCache: new QueryCache({ + onError: (error) => handleAxiosError(error, dispatch, toast), + }), + }); + return ( {children} ); diff --git a/apps/desk/src/renderer/src/providers/toast.tsx b/apps/desk/src/renderer/src/providers/toast.tsx deleted file mode 100644 index 23cb6903..00000000 --- a/apps/desk/src/renderer/src/providers/toast.tsx +++ /dev/null @@ -1 +0,0 @@ -export const toastProvider = ({ children }) => {}; diff --git a/apps/desk/src/renderer/src/store/slices/auth.slice.ts b/apps/desk/src/renderer/src/store/slices/auth.slice.ts index 02808b61..d15a156a 100644 --- a/apps/desk/src/renderer/src/store/slices/auth.slice.ts +++ b/apps/desk/src/renderer/src/store/slices/auth.slice.ts @@ -1,8 +1,16 @@ import { PayloadAction, createSlice } from '@reduxjs/toolkit'; +export type Role = 'Owner' | 'Admin' | 'User'; + +export type UserType = 'ORGANIZATION_USER' | 'SOLUTION_OWNER'; export type AuthPayloadType = { isAuth: boolean; token: string | null; + userId: string; + organizationId: string; + isAccountActivated: boolean; + role: Role; + userType: UserType; }; export interface AuthSliceType { @@ -10,7 +18,15 @@ export interface AuthSliceType { } const initialState: AuthSliceType = { - auth: { isAuth: false, token: localStorage.getItem('token') }, + auth: { + isAuth: false, + token: localStorage.getItem('token'), + userId: '', + organizationId: '', + role: 'User', + userType: 'ORGANIZATION_USER', + isAccountActivated: false, + }, }; const authSlice = createSlice({ @@ -26,10 +42,31 @@ const authSlice = createSlice({ ) => { state.auth.token = token; }, - reset: () => ({ auth: { isAuth: false, token: null } }), + setUserData: ( + state: AuthSliceType, + { payload }: PayloadAction> + ) => { + state.auth = { ...state.auth, ...payload }; + }, + reset: () => ({ + auth: { + isAuth: false, + token: null, + userId: '', + organizationId: '', + role: 'User' as Role, + userType: 'ORGANIZATION_USER' as UserType, + isAccountActivated: false, + }, + }), }, }); -export const { setIsAuth, setToken, reset: resetAuth } = authSlice.actions; +export const { + setIsAuth, + setToken, + setUserData, + reset: resetAuth, +} = authSlice.actions; export default authSlice.reducer; diff --git a/apps/desk/src/renderer/src/utils/schemas/formSchema.ts b/apps/desk/src/renderer/src/utils/schemas/formSchema.ts index 8f618fa9..c8fd12a3 100644 --- a/apps/desk/src/renderer/src/utils/schemas/formSchema.ts +++ b/apps/desk/src/renderer/src/utils/schemas/formSchema.ts @@ -66,25 +66,25 @@ export const EditProfileSchema = z .string() .email({ message: 'Invalid email address.' }) .min(1, { message: 'Email is required.' }), - currentPassword: z - .string() - .min(6, { message: 'Current password must be at least 6 characters.' }), - newPassword: z - .string() - .min(6, { message: 'New password must be at least 6 characters.' }), - confirmPassword: z - .string() - .min(6, { message: 'Confirm password must be at least 6 characters.' }), + // currentPassword: z + // .string() + // .min(6, { message: 'Current password must be at least 6 characters.' }), + // newPassword: z + // .string() + // .min(6, { message: 'New password must be at least 6 characters.' }), + // confirmPassword: z + // .string() + // .min(6, { message: 'Confirm password must be at least 6 characters.' }), }) - .refine( - (values) => { - return values.newPassword === values.confirmPassword; - }, - { - message: 'Passwords must match!', - path: ['confirmPassword'], - } - ); + // .refine( + // (values) => { + // return values.newPassword === values.confirmPassword; + // }, + // { + // message: 'Passwords must match!', + // path: ['confirmPassword'], + // } + // ); export type OrganizationFormData = z.infer; export type MemberFormData = z.infer; diff --git a/apps/web/src/app/signup/components/PersonalInfosForm.tsx b/apps/web/src/app/signup/components/PersonalInfosForm.tsx index ecc33716..2dade949 100644 --- a/apps/web/src/app/signup/components/PersonalInfosForm.tsx +++ b/apps/web/src/app/signup/components/PersonalInfosForm.tsx @@ -6,11 +6,13 @@ import { useForm } from 'react-hook-form'; interface PersonalInfosProps { setStep: React.Dispatch>; onSubmit: (data: any) => void; + isLoading: boolean; } const PersonalInfosForm: React.FC = ({ setStep, onSubmit, + isLoading, }) => { const { register, @@ -21,94 +23,98 @@ const PersonalInfosForm: React.FC = ({ }); return ( -
+

Personal Information

- +
+ - + - + - + - {/* Add the new fields here */} - + {/* Add the new fields here */} + - + - + -
- - +
+ + +
@@ -120,9 +126,10 @@ const PersonalInfosForm: React.FC = ({
diff --git a/apps/web/src/app/signup/page.tsx b/apps/web/src/app/signup/page.tsx index 3fee5251..c62a529b 100644 --- a/apps/web/src/app/signup/page.tsx +++ b/apps/web/src/app/signup/page.tsx @@ -85,6 +85,7 @@ const SignUpPage: React.FC = () => { )} {step === 2 && ( diff --git a/apps/web/src/hooks/useSignUp.ts b/apps/web/src/hooks/useSignUp.ts index a81f25be..bd8f3730 100644 --- a/apps/web/src/hooks/useSignUp.ts +++ b/apps/web/src/hooks/useSignUp.ts @@ -1,5 +1,4 @@ import { api } from '@/api'; -import { errorToast } from '@/lib/toasts'; import { useMutation, UseMutationOptions } from '@tanstack/react-query'; import { AxiosResponse } from 'axios'; @@ -13,7 +12,7 @@ export const useSignup = ( ...options, - onError: (error) => errorToast(error.message), + onError: (error) => {}, }); return { diff --git a/apps/web/src/lib/toasts.ts b/apps/web/src/lib/toasts.ts deleted file mode 100644 index 23e28c8e..00000000 --- a/apps/web/src/lib/toasts.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { toast } from 'react-toastify'; - -export const putNotification = (title: string, body: string) => { - new window.Notification(title, { body: body }); -}; - -export const errorToast = (errorMessage: string) => { - toast.error(errorMessage, { - position: 'top-right', - autoClose: 5000, - hideProgressBar: false, - closeOnClick: true, - pauseOnHover: true, - draggable: true, - progress: undefined, - theme: 'light', - }); -}; - -export const successToast = (message: string) => { - toast.success(message, { - position: 'top-right', - autoClose: 5000, - hideProgressBar: false, - closeOnClick: true, - pauseOnHover: true, - draggable: true, - progress: undefined, - theme: 'light', - }); -}; - -export const infoToast = (message: string) => { - toast.info(message, { - position: 'top-right', - autoClose: 5000, - hideProgressBar: false, - closeOnClick: true, - pauseOnHover: true, - draggable: true, - progress: undefined, - theme: 'light', - }); -}; - -export const warningToast = (message: string) => { - toast.warning(message, { - position: 'top-right', - autoClose: 5000, - hideProgressBar: false, - closeOnClick: true, - pauseOnHover: true, - draggable: true, - progress: undefined, - theme: 'light', - }); -};