feat(sidebar): add calls section to navigation menu
This commit introduces a new "Calls" section to the main sidebar navigation to provide users with access to call logs. - Adds a new collapsible "Calls" menu item to the sidebar configuration. - Includes sub-links for "All Calls", "Incoming", "Outgoing", and "Missed" calls. - Creates new custom icons (GlobeSearch, CallIncome, CallMade, CallMissed, CallReceived) to support the new menu items. - Updates `apexcharts` and `react-apexcharts` dependencies to newer versions.
This commit is contained in:
@@ -107,6 +107,7 @@ export function UserInfo() {
|
||||
onClick={() => {
|
||||
setIsOpen(false);
|
||||
logout();
|
||||
|
||||
}}
|
||||
>
|
||||
<LogOutIcon />
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { GlobeSearch } from "@/assets/icons";
|
||||
import { z } from "zod";
|
||||
import * as Icons from "../icons";
|
||||
|
||||
@@ -72,6 +73,19 @@ export const NAV_DATA: NavData = [
|
||||
icon: Icons.NotificationIcon,
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: "Contact Us",
|
||||
url: "/contact-us",
|
||||
icon: Icons.CallIncome,
|
||||
items: [],
|
||||
visible: false,
|
||||
},
|
||||
{
|
||||
title: "Marketing",
|
||||
url: "/marketing",
|
||||
icon: GlobeSearch,
|
||||
items: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -19,6 +19,32 @@ export function ChevronUp(props: PropsType) {
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
export function CallIncome(props: PropsType) {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
{...props}
|
||||
>
|
||||
<path
|
||||
d="M21.97 18.33C21.97 18.69 21.89 19.06 21.72 19.42C21.55 19.78 21.33 20.12 21.04 20.44C20.55 20.98 20.01 21.37 19.4 21.62C18.8 21.87 18.15 22 17.45 22C16.43 22 15.34 21.76 14.19 21.27C13.04 20.78 11.89 20.12 10.75 19.29C9.6 18.45 8.51 17.52 7.47 16.49C6.44 15.45 5.51 14.36 4.68 13.22C3.86 12.08 3.2 10.94 2.72 9.81C2.24 8.67 2 7.58 2 6.54C2 5.86 2.12 5.21 2.36 4.61C2.6 4 2.98 3.44 3.51 2.94C4.15 2.31 4.85 2 5.59 2C5.87 2 6.15 2.06 6.4 2.18C6.66 2.3 6.89 2.48 7.07 2.74L9.39 6.01C9.57 6.26 9.7 6.49 9.79 6.71C9.88 6.92 9.93 7.13 9.93 7.32C9.93 7.56 9.86 7.8 9.72 8.03C9.59 8.26 9.4 8.5 9.16 8.74L8.4 9.53C8.29 9.64 8.24 9.77 8.24 9.93C8.24 10.01 8.25 10.08 8.27 10.16C8.3 10.24 8.33 10.3 8.35 10.36C8.53 10.69 8.84 11.12 9.28 11.64C9.73 12.16 10.21 12.69 10.73 13.22C11.27 13.75 11.79 14.24 12.32 14.69C12.84 15.13 13.27 15.43 13.61 15.61C13.66 15.63 13.72 15.66 13.79 15.69C13.87 15.72 13.95 15.73 14.04 15.73C14.21 15.73 14.34 15.67 14.45 15.56L15.21 14.81C15.46 14.56 15.7 14.37 15.93 14.25C16.16 14.11 16.39 14.04 16.64 14.04C16.83 14.04 17.03 14.08 17.25 14.17C17.47 14.26 17.7 14.39 17.95 14.56L21.26 16.91C21.52 17.09 21.7 17.3 21.81 17.55C21.91 17.8 21.97 18.05 21.97 18.33Z"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeMiterlimit="10"
|
||||
/>
|
||||
<path
|
||||
d="M16.2 7.8H21M16.2 7.8V3V7.8Z"
|
||||
stroke="currentColor"
|
||||
strokeWidth="1.5"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
export function NotificationIcon(props: PropsType) {
|
||||
return (
|
||||
<svg
|
||||
|
||||
@@ -21,9 +21,7 @@ import Link from "next/link";
|
||||
import { Tooltip } from "react-tooltip";
|
||||
import { useCompanyListPresenter } from "./useCompanyListPresenter";
|
||||
|
||||
interface IProps {}
|
||||
|
||||
const CompaniesTable = ({}: IProps) => {
|
||||
const CompaniesTable = () => {
|
||||
const {
|
||||
isPending,
|
||||
pathName,
|
||||
@@ -47,7 +45,7 @@ const CompaniesTable = ({}: IProps) => {
|
||||
{columns.map((columns) => (
|
||||
<TableHead
|
||||
colSpan={100}
|
||||
className="text-start font-extrabold uppercase"
|
||||
className="text-start uppercase"
|
||||
key={columns}
|
||||
>
|
||||
{columns}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
"use client";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import TableSkeleton from "@/components/ui/TableSkeleton";
|
||||
import { useContactUsListPresenter } from "./useContactUsListPresenter";
|
||||
|
||||
const ContactUsTable = () => {
|
||||
const { columns, pathname, router, isPending } = useContactUsListPresenter();
|
||||
return (
|
||||
<div className="flex flex-col rounded-[10px] bg-white px-7.5 pb-4 pt-7.5 shadow-1 dark:bg-gray-dark dark:shadow-card">
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
{columns.map((columns) => (
|
||||
<TableHead
|
||||
colSpan={100}
|
||||
className="text-start uppercase"
|
||||
key={columns}
|
||||
>
|
||||
{columns}
|
||||
</TableHead>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
{isPending && <TableSkeleton column={columns.length} />}
|
||||
<TableBody></TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ContactUsTable;
|
||||
@@ -0,0 +1,16 @@
|
||||
"use client";
|
||||
import { useReadAllContactUs } from "@/hooks/queries/useContactUsQuery";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
export const useContactUsListPresenter = () => {
|
||||
const columns: string[] = [];
|
||||
const pathname = usePathname();
|
||||
const router = useRouter();
|
||||
const { data, isPending } = useReadAllContactUs();
|
||||
return {
|
||||
columns,
|
||||
pathname,
|
||||
router,
|
||||
isPending,
|
||||
data,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,73 @@
|
||||
import InputGroup from "@/components/FormElements/InputGroup";
|
||||
import { Select } from "@/components/FormElements/select";
|
||||
import {
|
||||
FieldValues,
|
||||
UseFormHandleSubmit,
|
||||
UseFormRegister,
|
||||
UseFormSetValue,
|
||||
UseFormWatch,
|
||||
} from "react-hook-form";
|
||||
|
||||
interface NotificationHistoryListFiltersProps {
|
||||
filterRegister: UseFormRegister<FieldValues>;
|
||||
setIsFilterModalOpen: (isOpen: boolean) => void;
|
||||
isMutating: number;
|
||||
handleFilterSubmit: UseFormHandleSubmit<FieldValues>;
|
||||
search: (data: any) => void;
|
||||
watch: UseFormWatch<FieldValues>;
|
||||
setValue: UseFormSetValue<any>;
|
||||
}
|
||||
|
||||
const NotificationHistoryListFilters = ({
|
||||
filterRegister,
|
||||
setIsFilterModalOpen,
|
||||
isMutating,
|
||||
handleFilterSubmit,
|
||||
search,
|
||||
}: NotificationHistoryListFiltersProps) => {
|
||||
return (
|
||||
<form
|
||||
className="grid !min-w-full grid-cols-1 gap-4 xl:grid-cols-2"
|
||||
onSubmit={handleFilterSubmit(search)}
|
||||
>
|
||||
<Select
|
||||
{...filterRegister("seen")}
|
||||
items={[
|
||||
{ label: "Seen", value: "true" },
|
||||
{ label: "Not seen", value: "false" },
|
||||
]}
|
||||
label="Seen"
|
||||
name="seen"
|
||||
/>
|
||||
<InputGroup
|
||||
{...filterRegister("search")}
|
||||
name="search"
|
||||
label="search"
|
||||
placeholder="search"
|
||||
type="search"
|
||||
/>
|
||||
|
||||
<div className="flex gap-4">
|
||||
<button
|
||||
type="submit"
|
||||
className="mt-6 flex w-fit justify-center rounded-lg bg-primary p-[13px] font-medium capitalize text-white hover:bg-opacity-90"
|
||||
>
|
||||
{isMutating ? (
|
||||
<div className="h-5 w-5 animate-spin rounded-full border-b-2 border-gray-1"></div>
|
||||
) : (
|
||||
<span>Search</span>
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="mt-6 flex w-fit justify-center rounded-lg bg-error p-[13px] font-medium capitalize text-white hover:bg-opacity-90"
|
||||
onClick={() => setIsFilterModalOpen(false)}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotificationHistoryListFilters;
|
||||
@@ -14,10 +14,12 @@ import {
|
||||
import TableSkeleton from "@/components/ui/TableSkeleton";
|
||||
import { _TooltipDefaultParams } from "@/constants/tooltip";
|
||||
import { truncateString, unixToDate } from "@/utils/shared";
|
||||
import Link from "next/link";
|
||||
import { Tooltip } from "react-tooltip";
|
||||
|
||||
import Boolean from "@/components/ui/Boolean";
|
||||
import ListHeader from "@/components/ui/ListHeader";
|
||||
import Modal from "@/components/ui/modal";
|
||||
import NotificationHistoryListFilters from "./NotificationHistoryListFilters";
|
||||
import useNotificationHistoryTablePresenter from "./useNotificationHistoryTablePresenter";
|
||||
|
||||
const NotificationHistoryTable = () => {
|
||||
@@ -28,94 +30,122 @@ const NotificationHistoryTable = () => {
|
||||
notificationHistory,
|
||||
pathName,
|
||||
router,
|
||||
isFilterModalOpen,
|
||||
setIsFilterModalOpen,
|
||||
setParams,
|
||||
handleSubmit,
|
||||
register,
|
||||
setValue,
|
||||
watch,
|
||||
search,
|
||||
isMutating,
|
||||
} = useNotificationHistoryTablePresenter();
|
||||
|
||||
return (
|
||||
<ShowcaseSection className="flex flex-col">
|
||||
<button className="mb-5 flex w-fit justify-center self-end rounded-lg bg-primary p-[13px] font-medium text-white hover:bg-opacity-90">
|
||||
<Link href={`${pathName}/create`}>Create Notification </Link>
|
||||
</button>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
{columns.map((column) => (
|
||||
<TableHead colSpan={100} key={column}>
|
||||
{column}
|
||||
</TableHead>
|
||||
))}
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
{isLoading && <TableSkeleton column={columns.length} />}
|
||||
<TableBody>
|
||||
{!notificationHistory?.length ? (
|
||||
<>
|
||||
<ShowcaseSection className="flex flex-col">
|
||||
<ListHeader
|
||||
createButtonText="Create notification"
|
||||
onFilter={() => setIsFilterModalOpen(true)}
|
||||
/>
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<h2>No notifications</h2>
|
||||
</TableCell>
|
||||
{columns.map((column) => (
|
||||
<TableHead colSpan={100} key={column}>
|
||||
{column}
|
||||
</TableHead>
|
||||
))}
|
||||
</TableRow>
|
||||
) : (
|
||||
notificationHistory.map((item, index) => (
|
||||
<TableRow key={item.id}>
|
||||
<TableCell colSpan={100}>{index + 1}</TableCell>
|
||||
<TableCell colSpan={100}>{item.title}</TableCell>
|
||||
<TableCell colSpan={100}>{item.event_type}</TableCell>
|
||||
<TableCell colSpan={100}>
|
||||
{unixToDate({
|
||||
hasTime: true,
|
||||
unix: item.created_at,
|
||||
})}
|
||||
</TableCell>
|
||||
<TableCell colSpan={100}>{item.recipient?.full_name}</TableCell>
|
||||
<TableCell colSpan={100} className="truncate">
|
||||
{truncateString(item.message, 20, 20)}
|
||||
</TableCell>
|
||||
<TableCell className="capitalize" colSpan={100}>
|
||||
{item.priority}
|
||||
</TableCell>
|
||||
<TableCell className="capitalize" colSpan={100}>
|
||||
{item.type}
|
||||
</TableCell>
|
||||
<TableCell className="capitalize" colSpan={100}>
|
||||
<Boolean value={item.seen} />
|
||||
</TableCell>
|
||||
<TableCell colSpan={100}>
|
||||
<Status status={item.status}>{item.status}</Status>
|
||||
</TableCell>
|
||||
<TableCell colSpan={100}>
|
||||
<button
|
||||
data-tooltip-id="details"
|
||||
data-tooltip-content="Details"
|
||||
data-tooltip-place="top"
|
||||
onClick={() => {
|
||||
router.push(`${pathName}/${item.id}`);
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
{..._TooltipDefaultParams({
|
||||
id: "details",
|
||||
})}
|
||||
/>
|
||||
<EyeIcon />
|
||||
</button>
|
||||
</TableHeader>
|
||||
{isLoading && <TableSkeleton column={columns.length} />}
|
||||
<TableBody>
|
||||
{!notificationHistory?.length ? (
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<h2>No notifications</h2>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<Pagination
|
||||
currentPage={metadata?.page ? metadata?.page - 1 : 0}
|
||||
totalPages={metadata?.pages ?? 1}
|
||||
onPageChange={(e) => {
|
||||
setParams((currentParams) => ({
|
||||
...currentParams,
|
||||
offset: e.selected * (metadata?.limit ?? 10),
|
||||
limit: metadata?.limit ?? 10,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
</ShowcaseSection>
|
||||
) : (
|
||||
notificationHistory.map((item, index) => (
|
||||
<TableRow key={item.id}>
|
||||
<TableCell colSpan={100}>{index + 1}</TableCell>
|
||||
<TableCell colSpan={100}>{item.title}</TableCell>
|
||||
<TableCell colSpan={100}>{item.event_type}</TableCell>
|
||||
<TableCell colSpan={100}>
|
||||
{unixToDate({
|
||||
hasTime: true,
|
||||
unix: item.created_at,
|
||||
})}
|
||||
</TableCell>
|
||||
<TableCell colSpan={100}>
|
||||
{item.recipient?.full_name}
|
||||
</TableCell>
|
||||
<TableCell colSpan={100} className="truncate">
|
||||
{truncateString(item.message, 20, 20)}
|
||||
</TableCell>
|
||||
<TableCell className="capitalize" colSpan={100}>
|
||||
{item.priority}
|
||||
</TableCell>
|
||||
<TableCell className="capitalize" colSpan={100}>
|
||||
{item.type}
|
||||
</TableCell>
|
||||
<TableCell className="capitalize" colSpan={100}>
|
||||
<Boolean value={item.seen} />
|
||||
</TableCell>
|
||||
<TableCell colSpan={100}>
|
||||
<Status status={item.status}>{item.status}</Status>
|
||||
</TableCell>
|
||||
<TableCell colSpan={100}>
|
||||
<button
|
||||
data-tooltip-id="details"
|
||||
data-tooltip-content="Details"
|
||||
data-tooltip-place="top"
|
||||
onClick={() => {
|
||||
router.push(`${pathName}/${item.id}`);
|
||||
}}
|
||||
>
|
||||
<Tooltip
|
||||
{..._TooltipDefaultParams({
|
||||
id: "details",
|
||||
})}
|
||||
/>
|
||||
<EyeIcon />
|
||||
</button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
)}
|
||||
</TableBody>
|
||||
</Table>
|
||||
<Pagination
|
||||
currentPage={metadata?.page ? metadata?.page - 1 : 0}
|
||||
totalPages={metadata?.pages ?? 1}
|
||||
onPageChange={(e) => {
|
||||
setParams((currentParams) => ({
|
||||
...currentParams,
|
||||
offset: e.selected * (metadata?.limit ?? 10),
|
||||
limit: metadata?.limit ?? 10,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
</ShowcaseSection>
|
||||
<Modal
|
||||
isOpen={isFilterModalOpen}
|
||||
onClose={() => setIsFilterModalOpen(false)}
|
||||
showButtons={false}
|
||||
>
|
||||
<NotificationHistoryListFilters
|
||||
filterRegister={register}
|
||||
handleFilterSubmit={handleSubmit}
|
||||
isMutating={isMutating}
|
||||
watch={watch}
|
||||
setValue={setValue}
|
||||
setIsFilterModalOpen={setIsFilterModalOpen}
|
||||
search={search}
|
||||
/>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
"use client";
|
||||
import { apiDefaultParams } from "@/constants/Api_Params";
|
||||
import { useGetNotificationHistoryQuery } from "@/hooks/queries/useNotificationQueries";
|
||||
import { deleteEmptyKeys } from "@/utils/shared";
|
||||
import { useIsMutating } from "@tanstack/react-query";
|
||||
import { usePathname, useRouter } from "next/navigation";
|
||||
import { useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
||||
const useNotificationHistoryTablePresenter = () => {
|
||||
const { register, handleSubmit, watch, setValue } = useForm();
|
||||
const [isFilterModalOpen, setIsFilterModalOpen] = useState(false);
|
||||
const [params, setParams] = useState<Record<string, any>>({
|
||||
...apiDefaultParams,
|
||||
});
|
||||
const { data, isLoading } = useGetNotificationHistoryQuery(params);
|
||||
|
||||
const isMutating = useIsMutating();
|
||||
const columns: string[] = [
|
||||
"row",
|
||||
"title",
|
||||
@@ -25,6 +30,14 @@ const useNotificationHistoryTablePresenter = () => {
|
||||
];
|
||||
const pathName = usePathname();
|
||||
const router = useRouter();
|
||||
const search = (data: any) => {
|
||||
const newParams = { ...params, ...data, offset: 0 };
|
||||
const cleanedParams = deleteEmptyKeys(newParams);
|
||||
setParams(cleanedParams);
|
||||
const queryString = new URLSearchParams(cleanedParams).toString();
|
||||
router.push(`${pathName}?${queryString}`);
|
||||
setIsFilterModalOpen(false);
|
||||
};
|
||||
return {
|
||||
notificationHistory: data?.data,
|
||||
metadata: data?.meta,
|
||||
@@ -33,6 +46,14 @@ const useNotificationHistoryTablePresenter = () => {
|
||||
router,
|
||||
pathName,
|
||||
setParams,
|
||||
register,
|
||||
handleSubmit,
|
||||
watch,
|
||||
setValue,
|
||||
isFilterModalOpen,
|
||||
setIsFilterModalOpen,
|
||||
isMutating,
|
||||
search,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
import { CheckIcon } from "@/assets/icons";
|
||||
import React, { ReactNode, useState } from "react";
|
||||
export interface Step {
|
||||
title: string;
|
||||
description?: string;
|
||||
content: ReactNode;
|
||||
}
|
||||
|
||||
interface StepperProps {
|
||||
steps: Step[];
|
||||
currentStep?: number;
|
||||
onStepChange?: (step: number) => void;
|
||||
}
|
||||
|
||||
const Stepper: React.FC<StepperProps> = ({
|
||||
steps,
|
||||
currentStep: controlledStep,
|
||||
onStepChange,
|
||||
}) => {
|
||||
const [internalStep, setInternalStep] = useState(0);
|
||||
const currentStep =
|
||||
controlledStep !== undefined ? controlledStep : internalStep;
|
||||
|
||||
const handleStepClick = (index: number) => {
|
||||
if (index <= currentStep) {
|
||||
if (onStepChange) {
|
||||
onStepChange(index);
|
||||
} else {
|
||||
setInternalStep(index);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const nextStep = () => {
|
||||
if (currentStep < steps.length - 1) {
|
||||
const newStep = currentStep + 1;
|
||||
if (onStepChange) {
|
||||
onStepChange(newStep);
|
||||
} else {
|
||||
setInternalStep(newStep);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const prevStep = () => {
|
||||
if (currentStep > 0) {
|
||||
const newStep = currentStep - 1;
|
||||
if (onStepChange) {
|
||||
onStepChange(newStep);
|
||||
} else {
|
||||
setInternalStep(newStep);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-4xl p-8">
|
||||
<div className="mb-8 flex items-center justify-between">
|
||||
{steps.map((step, index) => (
|
||||
<React.Fragment key={index}>
|
||||
<div className="flex flex-1 flex-col items-center">
|
||||
<button
|
||||
onClick={() => handleStepClick(index)}
|
||||
disabled={index > currentStep}
|
||||
className={`flex h-12 w-12 items-center justify-center rounded-full font-semibold transition-all duration-200 ${
|
||||
index < currentStep
|
||||
? "cursor-pointer bg-primary text-white hover:bg-primary/90"
|
||||
: index === currentStep
|
||||
? "bg-primary text-white ring-4 ring-primary/20"
|
||||
: "cursor-not-allowed bg-gray-2 text-gray-5"
|
||||
}`}
|
||||
>
|
||||
{index < currentStep ? (
|
||||
<CheckIcon className="h-6 w-6" />
|
||||
) : (
|
||||
<span>{index + 1}</span>
|
||||
)}
|
||||
</button>
|
||||
<div className="mt-2 text-center">
|
||||
<div
|
||||
className={`text-sm font-medium ${
|
||||
index <= currentStep ? "text-dark-2" : "text-gray-4"
|
||||
}`}
|
||||
>
|
||||
{step.title}
|
||||
</div>
|
||||
{step.description && (
|
||||
<div className="mt-1 text-xs text-gray-5">
|
||||
{step.description}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{index < steps.length - 1 && (
|
||||
<div
|
||||
className={`mx-4 -mt-12 h-1 flex-1 transition-all duration-300 ${
|
||||
index < currentStep ? "bg-primary" : "bg-stroke"
|
||||
}`}
|
||||
/>
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div>{steps[currentStep].content}</div>
|
||||
|
||||
<div className="mt-6 flex justify-between">
|
||||
<button
|
||||
onClick={prevStep}
|
||||
disabled={currentStep === 0}
|
||||
className={`rounded-lg px-6 py-2 font-medium transition-all ${
|
||||
currentStep === 0
|
||||
? "cursor-not-allowed bg-gray-1 text-gray-4"
|
||||
: "bg-gray-2 text-gray-7 hover:bg-gray-3"
|
||||
}`}
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
<button
|
||||
onClick={nextStep}
|
||||
disabled={currentStep === steps.length - 1}
|
||||
className={`rounded-lg px-6 py-2 font-medium transition-all ${
|
||||
currentStep === steps.length - 1
|
||||
? "cursor-not-allowed bg-gray-1 text-gray-4"
|
||||
: "bg-primary text-white hover:bg-primary/90"
|
||||
}`}
|
||||
>
|
||||
{currentStep === steps.length - 1 ? "Completed" : "Next"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Stepper;
|
||||
Reference in New Issue
Block a user