feat(settings): implement user profile page and notification handler
This commit introduces a new user settings page and enhances push notification functionality. The new settings page, located at `/pages/settings`, allows users to view and update their personal profile information. It fetches the current user's data and provides a form to edit fields such as name, email, phone number, position, and role. The form is built using `react-hook-form` for state management and validation, and it leverages custom hooks (`useProfileQuery`, `useUpdateProfileQuery`) to interact with the API. Additionally, a `notificationclick` event listener has been added to the Firebase messaging service worker. This handler improves the user experience for push notifications by focusing on an existing tab with the relevant URL or opening a new one if none exists when a notification is clicked.
This commit is contained in:
@@ -16,8 +16,7 @@ export default function SigninWithPassword() {
|
||||
const [passwordFieldInputType, setPasswordFieldInputType] = useState<
|
||||
"password" | "text"
|
||||
>("password");
|
||||
const { handleSubmit, control, reset, register } =
|
||||
useForm<ILoginCredentials>();
|
||||
const { handleSubmit, reset, register } = useForm<ILoginCredentials>();
|
||||
const { mutate } = useLoginQuery(reset);
|
||||
|
||||
const onSubmit: SubmitHandler<ILoginCredentials> = (data) => {
|
||||
|
||||
@@ -60,7 +60,7 @@ const InputGroup = <T extends FieldValues>({
|
||||
<div className={className}>
|
||||
<label
|
||||
htmlFor={id}
|
||||
className="text-body-sm font-medium text-dark dark:text-white"
|
||||
className="text-body-sm font-medium capitalize text-dark dark:text-white"
|
||||
>
|
||||
{label}
|
||||
{required && <span className="ml-1 select-none text-error">*</span>}
|
||||
@@ -93,7 +93,7 @@ const InputGroup = <T extends FieldValues>({
|
||||
defaultValue: props.defaultValue,
|
||||
})}
|
||||
className={cn(
|
||||
"w-full rounded-lg border-[1.5px] border-stroke bg-transparent outline-none transition focus:border-primary disabled:cursor-default disabled:bg-gray-2 data-[active=true]:border-primary dark:border-dark-3 dark:bg-dark-2 dark:focus:border-primary dark:disabled:bg-dark dark:data-[active=true]:border-primary",
|
||||
"w-full rounded-lg border-[1.5px] border-stroke bg-transparent outline-none transition placeholder:capitalize focus:border-primary disabled:cursor-default disabled:bg-gray-2 data-[active=true]:border-primary dark:border-dark-3 dark:bg-dark-2 dark:focus:border-primary dark:disabled:bg-dark dark:data-[active=true]:border-primary",
|
||||
// Add error styles conditionally
|
||||
error && "border-red focus:border-red dark:border-red",
|
||||
type === "file"
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
import { ChevronUpIcon } from "@/assets/icons";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { ILabelValue } from "@/types/shared";
|
||||
import { useId, useState, type ChangeEvent } from "react";
|
||||
import {
|
||||
type FieldErrors,
|
||||
@@ -14,7 +15,7 @@ import {
|
||||
type PropsType<T extends FieldValues> = {
|
||||
name: Path<T>;
|
||||
label: string;
|
||||
items: { value: string; label: string }[];
|
||||
items: ILabelValue[];
|
||||
prefixIcon?: React.ReactNode;
|
||||
onChange?: (e: ChangeEvent<HTMLSelectElement>) => void;
|
||||
className?: string;
|
||||
|
||||
@@ -110,7 +110,7 @@ const NotificationHistoryTable = () => {
|
||||
setParams((currentParams) => ({
|
||||
...currentParams,
|
||||
offset: e.selected * (metadata?.limit ?? 10),
|
||||
limit: metadata?.limit ?? 1000,
|
||||
limit: metadata?.limit ?? 10,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import InputGroup from "@/components/FormElements/InputGroup";
|
||||
import { ShowcaseSection } from "@/components/Layouts/showcase-section";
|
||||
import FormFooter from "@/components/ui/FormFooter";
|
||||
import { REGEX } from "@/constants/regex";
|
||||
import { FormErrorMessages } from "@/constants/Texts";
|
||||
import { ICreateAdminCredentials } from "@/lib/api";
|
||||
import { FC } from "react";
|
||||
@@ -12,7 +13,7 @@ interface IProps {
|
||||
id?: string;
|
||||
}
|
||||
const CreateAdminForm: FC<IProps> = ({ defaultValues, editMode, id }) => {
|
||||
const { errors, handleSubmit, register, router, onSubmit } =
|
||||
const { errors, handleSubmit, register, onSubmit } =
|
||||
useCreateAdminPresenter({
|
||||
editMode,
|
||||
defaultValues,
|
||||
@@ -162,6 +163,10 @@ const CreateAdminForm: FC<IProps> = ({ defaultValues, editMode, id }) => {
|
||||
value: 20,
|
||||
message: FormErrorMessages.maxLength(20),
|
||||
},
|
||||
pattern:{
|
||||
value:REGEX.PHONE,
|
||||
message:FormErrorMessages.invalidPattern
|
||||
},
|
||||
})}
|
||||
name="phone"
|
||||
/>
|
||||
|
||||
@@ -10,6 +10,8 @@ import { REGEX } from "@/constants/regex";
|
||||
import { FormErrorMessages } from "@/constants/Texts";
|
||||
import { CreateCustomerCredentials } from "@/lib/api";
|
||||
import useCreateCustomerPresenter from "./useCreateCustomerPresenter";
|
||||
import { getEnumAsArray } from "@/utils/shared";
|
||||
import { AdminRoles } from "@/constants/enums";
|
||||
|
||||
interface IProps {
|
||||
editMode?: boolean;
|
||||
@@ -97,16 +99,7 @@ const CreateCustomer = ({ defaultValues, editMode, id }: IProps) => {
|
||||
required: { message: FormErrorMessages.required, value: true },
|
||||
})}
|
||||
name="role"
|
||||
items={[
|
||||
{
|
||||
label: "Admin",
|
||||
value: "admin",
|
||||
},
|
||||
{
|
||||
label: "Analyst",
|
||||
value: "analyst",
|
||||
},
|
||||
]}
|
||||
items={getEnumAsArray(AdminRoles)}
|
||||
placeholder="Select Role"
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user