This commit is contained in:
Moaz Dawalibi 2024-09-18 13:17:48 +03:00
parent 3a877b5053
commit e0e2839cf3
30 changed files with 893 additions and 21 deletions

View File

@ -0,0 +1,20 @@
import React, { useEffect, useState } from 'react'
export const useWindowResize = () => {
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
useEffect(() => {
window.addEventListener('resize', handleResize);
// Cleanup function to remove the event listener
return () => {
window.removeEventListener('resize', handleResize);
};
}, [windowWidth]);
const handleResize = () => {
setWindowWidth(window.innerWidth);
};
return {windowWidth , handleResize};
}

View File

@ -66,7 +66,7 @@ const SideBar = ({
</div> </div>
<div className="side_bar_setting"> <div className="side_bar_setting">
<p>{t("sidebar.setting")}</p> <p>{t("sidebar.setting")}</p>
<div> <div onClick={() => {navigate("/setting")}}>
<CiSettings /> <CiSettings />
<span>{t("sidebar.setting")}</span> <span>{t("sidebar.setting")}</span>
</div> </div>

View File

@ -0,0 +1,42 @@
import TabHeader from './TabHeader'
import { Form, Formik } from 'formik'
import { getInitialValues, getValidationSchema } from './FileSetting/formUtils'
import PersonalDetailsForm from './FileSetting/PersonalDetailsForm'
import TitleDetailsForm from './FileSetting/TitleDetailsForm'
import AttachmentForm from './FileSetting/AttachmentForm'
import { useTranslation } from 'react-i18next'
const FileSetting = () => {
const {t} = useTranslation()
const handelSubmit = (values: any) => {
console.log(values, "values");
};
return (
<div className='file_setting'>
<TabHeader
name='file_setting'
description='upload_your_photo_and_personal_data_here'
>
<div className="file_setting_buttons">
<button type="button">{t("practical.cancel")}</button>
<button type="submit">
{t("practical.save")}
</button>
</div>
</TabHeader>
<Formik
initialValues={getInitialValues({})}
validationSchema={getValidationSchema}
onSubmit={handelSubmit}
>
<Form className="Form_details_container">
<PersonalDetailsForm />
<TitleDetailsForm />
<AttachmentForm />
</Form>
</Formik>
</div>
)
}
export default FileSetting

View File

@ -0,0 +1,23 @@
import React from "react";
import { useTranslation } from "react-i18next";
import { FaImage, FaStore } from "react-icons/fa";
import ImageBoxField from "./ImageBoxField/ImageBoxField";
const AttachmentForm = () => {
const [t] = useTranslation();
return (
<div className="AttachmentForm">
<header className="header_form">
<FaStore />
<h4>{t("header.attachments")}</h4>
</header>
<main className="main_form_body">
<ImageBoxField name="personal_image" />
<ImageBoxField name="id_image" />
</main>
</div>
);
};
export default AttachmentForm;

View File

@ -0,0 +1,38 @@
.ImageBoxField {
.ImageBox {
width: 120px;
height: 120px;
display: flex;
align-items: center;
justify-content: center;
border: max(1.5px, 0.1vw) dashed #a9c3f1;
margin-block: 10px;
border-radius: 5px;
z-index: 9999999 !important;
.ImageBoxIcon {
cursor: pointer;
}
.imagePreview {
max-width: 99%;
height: auto;
max-height: 99%;
object-fit: contain;
border-radius: 5px;
}
}
.ImageHeader {
display: flex;
align-items: center;
justify-content: flex-end;
gap: 10px;
}
.ImageCancelIcon {
width: 16px !important;
height: 16px !important;
}
.ImageBoxIcon {
width: 20px !important;
height: 20px !important;
}
}

View File

@ -0,0 +1,87 @@
import { useFormikContext } from "formik";
import { useState, useRef, useEffect } from "react";
import "./ImageBoxField.scss";
import ImageIcon from "./ImageIcon";
import ImageCancelIcon from "./ImageCancelIcon";
import { generateImagePreview } from "./generateImagePreview";
import { getNestedValue } from "../../../../../../utils/getNestedValue";
import { useTranslation } from "react-i18next";
// Helper function to generate image preview from a File
const ImageBoxField = ({ name }: any) => {
const formik = useFormikContext<any>();
const value = getNestedValue(formik.values, name);
const [imagePreview, setImagePreview] = useState<string | null>(null);
const fileInputRef = useRef<HTMLInputElement | null>(null);
useEffect(() => {
if (value instanceof File) {
generateImagePreview(value, setImagePreview);
} else if (typeof value === "string") {
setImagePreview(value);
} else {
setImagePreview(null);
}
}, [value]);
const handleFileChange = (event: any) => {
const file = event.target.files[0];
if (file) {
generateImagePreview(file, setImagePreview);
formik.setFieldValue(name, file);
}
};
const handleButtonClick = () => {
const fileInput = fileInputRef.current;
if (fileInput) {
fileInput.click();
}
};
const handleCancel = () => {
setImagePreview("");
formik.setFieldValue(name, "");
if (fileInputRef.current) {
fileInputRef.current.value = "";
}
};
const [t] = useTranslation();
return (
<div className="ImageBoxField">
<header>{t(`input.${name}`)}</header>
<div className="ImageHeader">
{imagePreview ? (
<>
<ImageCancelIcon
onClick={handleCancel}
className="ImageCancelIcon"
/>
<ImageIcon onClick={handleButtonClick} className="ImageBoxIcon" />
</>
) : (
<div className="VisibleHidden">hidden</div>
)}
</div>
<div className="ImageBox">
{imagePreview ? (
<img src={imagePreview} alt="Preview" className="imagePreview" />
) : (
<ImageIcon onClick={handleButtonClick} className="ImageBoxIcon" />
)}
</div>
<input
id={`file-input-${name}`}
type="file"
accept="image/png, image/jpeg, image/webp"
style={{ display: "none" }}
onChange={handleFileChange}
ref={fileInputRef}
/>
</div>
);
};
export default ImageBoxField;

View File

@ -0,0 +1,18 @@
import React from "react";
interface ImageCancelIconProps extends React.HTMLAttributes<HTMLDivElement> {}
const ImageCancelIcon: React.FC<ImageCancelIconProps> = (props) => {
return (
<div {...props}>
<svg viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M7 5.44469L12.4447 0L14 1.55531L8.55531 7L14 12.4447L12.4436 14L6.9989 8.55531L1.55531 14L0 12.4436L5.44469 6.9989L0 1.55421L1.55531 0.00109986L7 5.44469Z"
fill="#515B73"
/>
</svg>
</div>
);
};
export default ImageCancelIcon;

View File

@ -0,0 +1,18 @@
import React from "react";
interface ImageIconProps extends React.HTMLAttributes<HTMLDivElement> {}
const ImageIcon: React.FC<ImageIconProps> = (props) => {
return (
<div {...props}>
<svg viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M11.25 5.625C11.25 7.11684 10.6574 8.54758 9.60248 9.60248C8.54758 10.6574 7.11684 11.25 5.625 11.25C4.13316 11.25 2.70242 10.6574 1.64752 9.60248C0.592632 8.54758 0 7.11684 0 5.625C0 4.13316 0.592632 2.70242 1.64752 1.64752C2.70242 0.592632 4.13316 0 5.625 0C7.11684 0 8.54758 0.592632 9.60248 1.64752C10.6574 2.70242 11.25 4.13316 11.25 5.625ZM6.25 3.125C6.25 2.95924 6.18415 2.80027 6.06694 2.68306C5.94973 2.56585 5.79076 2.5 5.625 2.5C5.45924 2.5 5.30027 2.56585 5.18306 2.68306C5.06585 2.80027 5 2.95924 5 3.125V5H3.125C2.95924 5 2.80027 5.06585 2.68306 5.18306C2.56585 5.30027 2.5 5.45924 2.5 5.625C2.5 5.79076 2.56585 5.94973 2.68306 6.06694C2.80027 6.18415 2.95924 6.25 3.125 6.25H5V8.125C5 8.29076 5.06585 8.44973 5.18306 8.56694C5.30027 8.68415 5.45924 8.75 5.625 8.75C5.79076 8.75 5.94973 8.68415 6.06694 8.56694C6.18415 8.44973 6.25 8.29076 6.25 8.125V6.25H8.125C8.29076 6.25 8.44973 6.18415 8.56694 6.06694C8.68415 5.94973 8.75 5.79076 8.75 5.625C8.75 5.45924 8.68415 5.30027 8.56694 5.18306C8.44973 5.06585 8.29076 5 8.125 5H6.25V3.125ZM16.25 3.75H12.2413C12.1187 3.3183 11.9542 2.89964 11.75 2.5H16.25C17.2446 2.5 18.1984 2.89509 18.9017 3.59835C19.6049 4.30161 20 5.25544 20 6.25V16.25C20 17.2446 19.6049 18.1984 18.9017 18.9017C18.1984 19.6049 17.2446 20 16.25 20H6.25C5.25544 20 4.30161 19.6049 3.59835 18.9017C2.89509 18.1984 2.5 17.2446 2.5 16.25V11.75C2.89667 11.9533 3.31333 12.1171 3.75 12.2413V16.25C3.75 16.7162 3.8775 17.1525 4.1 17.525L9.93625 11.79C10.2869 11.4457 10.7586 11.2528 11.25 11.2528C11.7414 11.2528 12.2131 11.4457 12.5637 11.79L18.4012 17.525C18.6298 17.139 18.7502 16.6986 18.75 16.25V6.25C18.75 5.58696 18.4866 4.95107 18.0178 4.48223C17.5489 4.01339 16.913 3.75 16.25 3.75ZM16.25 8.125C16.25 8.37123 16.2015 8.61505 16.1073 8.84253C16.013 9.07002 15.8749 9.27672 15.7008 9.45083C15.5267 9.62494 15.32 9.76305 15.0925 9.85727C14.865 9.9515 14.6212 10 14.375 10C14.1288 10 13.885 9.9515 13.6575 9.85727C13.43 9.76305 13.2233 9.62494 13.0492 9.45083C12.8751 9.27672 12.737 9.07002 12.6427 8.84253C12.5485 8.61505 12.5 8.37123 12.5 8.125C12.5 7.62772 12.6975 7.15081 13.0492 6.79917C13.4008 6.44754 13.8777 6.25 14.375 6.25C14.8723 6.25 15.3492 6.44754 15.7008 6.79917C16.0525 7.15081 16.25 7.62772 16.25 8.125ZM15 8.125C15 7.95924 14.9342 7.80027 14.8169 7.68306C14.6997 7.56585 14.5408 7.5 14.375 7.5C14.2092 7.5 14.0503 7.56585 13.9331 7.68306C13.8158 7.80027 13.75 7.95924 13.75 8.125C13.75 8.29076 13.8158 8.44973 13.9331 8.56694C14.0503 8.68415 14.2092 8.75 14.375 8.75C14.5408 8.75 14.6997 8.68415 14.8169 8.56694C14.9342 8.44973 15 8.29076 15 8.125ZM4.985 18.4075C5.36871 18.6321 5.80538 18.7504 6.25 18.75H16.25C16.7125 18.75 17.1437 18.625 17.515 18.4075L11.6875 12.6825C11.5707 12.568 11.4136 12.5038 11.25 12.5038C11.0864 12.5038 10.9293 12.568 10.8125 12.6825L4.985 18.4075Z"
fill="#515B73"
/>
</svg>
</div>
);
};
export default ImageIcon;

View File

@ -0,0 +1,10 @@
export const generateImagePreview = (
file: File,
setImagePreview: (result: string) => void,
) => {
const reader = new FileReader();
reader.onloadend = () => {
setImagePreview(reader.result as string);
};
reader.readAsDataURL(file);
};

View File

@ -0,0 +1,52 @@
import { useTranslation } from "react-i18next";
import { FaStore } from "react-icons/fa";
import ValidationField from "../../../../../Components/ValidationField/ValidationField";
import { statusType } from "../../../../../config/statusType";
import { Col } from "antd";
const PersonalDetailsForm = () => {
const [t] = useTranslation();
return (
<div className="PersonalDetailsForm">
<header className="header_form">
<FaStore />
<h4>{t("header.personal_information")}</h4>
</header>
<main className="main_form_body">
<ValidationField
name={"first_name"}
placeholder={"_"}
label={"first_name"}
/>
<ValidationField
name={"last_name"}
placeholder={"_"}
type="Date"
label={"last_name"}
/>
<ValidationField
name={"email_address"}
placeholder={"_"}
label={"email_address"}
type="Select"
option={statusType}
/>
<ValidationField
name={"username"}
placeholder={"_"}
label={"username"}
/>
<ValidationField
name={"full_name"}
placeholder={"_"}
label={"Phone Number"}
/>
</main>
</div>
);
};
export default PersonalDetailsForm;

View File

@ -0,0 +1,30 @@
import { useTranslation } from "react-i18next";
import { FaStore } from "react-icons/fa";
import ValidationField from "../../../../../Components/ValidationField/ValidationField";
import { nationalities } from "../../../../../types/App";
import { CiEdit } from "react-icons/ci";
const TitleDetailsForm = () => {
const [t] = useTranslation();
return (
<div className="TitleDetailsForm">
<header className="header_form">
<FaStore />
<h4>{t("header.address")}</h4>
</header>
<main className="main_form_body">
<ValidationField
name={"city_id"}
placeholder={"_"}
label={"city"}
type="Select"
option={nationalities}
/>
<ValidationField name={"address"} placeholder={"_"} label={"address"} />
</main>
</div>
);
};
export default TitleDetailsForm;

View File

@ -0,0 +1,13 @@
import * as Yup from "yup";
export const getInitialValues = (objectToEdit: Partial<any>) => {
return {
id: objectToEdit?.id ?? null,
name: objectToEdit?.name ?? null,
};
};
export const getValidationSchema = () => {
// validate input
return Yup.object().shape({});
};

View File

@ -0,0 +1,36 @@
import React from 'react'
import TabHeader from './TabHeader'
import NotificationCard from './Notification/NotificationCard'
import { NotificationData } from '../../../../faker/item'
import { Form, Formik } from 'formik'
import { getInitialValues, getValidationSchema } from './Notification/formUtils'
const Notification = () => {
const handelSubmit = (values: any) => {
console.log(values, "values");
};
return (
<div className='notification'>
<TabHeader
name='notification'
description='get_notified_of_whats_happening_now_you_can_turn_it_off_at_any_time'
>
</TabHeader>
<Formik
initialValues={getInitialValues({})}
validationSchema={getValidationSchema}
onSubmit={handelSubmit}
>
<Form className="Form_details_container">
<div className='setting_notification_body'>
{NotificationData?.map((not: any) => (
<NotificationCard name={not.label} description={not?.value} />
))}
</div>
</Form>
</Formik>
</div>
)
}
export default Notification

View File

@ -0,0 +1,27 @@
import { useTranslation } from "react-i18next"
import ValidationField from "../../../../../Components/ValidationField/ValidationField";
const NotificationCard = ({
name,
description,
}:{
name:string,
description:string,
}) => {
const {t} = useTranslation();
return (
<div className='notification_card'>
<div>
<h5>{t(`${name}`)}</h5>
<p>{t(`${description}`)}</p>
</div>
<div>
<ValidationField type="Checkbox" name="name" label="empty"/>
</div>
</div>
)
}
export default NotificationCard

View File

@ -0,0 +1,13 @@
import * as Yup from "yup";
export const getInitialValues = (objectToEdit: Partial<any>) => {
return {
id: objectToEdit?.id ?? null,
name: objectToEdit?.name ?? null,
};
};
export const getValidationSchema = () => {
// validate input
return Yup.object().shape({});
};

View File

@ -0,0 +1,29 @@
import React from 'react'
import TabHeader from './TabHeader'
import SecurityCard from './SecuritySetting/SecurityCard'
import { Button } from 'antd'
import { SecurityData } from './SecuritySetting/SecurityData'
import { SettingType } from '../../../../types/Setting'
const SecuritySetting = () => {
return (
<div className='security_setting'>
<TabHeader
name='security_setting'
description='upload_your_photo_and_personal_data_here'
>
</TabHeader>
<div className='security_setting_body'>
{SecurityData?.map((e:SettingType)=>(
<SecurityCard
name={e?.name}
description={e?.description}
children={e?.children}/>
))}
</div>
</div>
)
}
export default SecuritySetting

View File

@ -0,0 +1,27 @@
import { useTranslation } from "react-i18next"
import ValidationField from "../../../../../Components/ValidationField/ValidationField";
import { ReactElement } from "react";
import { SettingType } from "../../../../../types/Setting";
const SecurityCard = ({
name,
description,
children
}:SettingType) => {
const {t} = useTranslation();
return (
<div className='security_card'>
<div>
<h5>{t(`practical.${name}`)}</h5>
<p>{t(`practical.${description}`)}</p>
</div>
<div>
{children}
</div>
</div>
)
}
export default SecurityCard

View File

@ -0,0 +1,47 @@
import { Button } from "antd";
import { SettingType } from "../../../../../types/Setting";
export const SecurityData:SettingType[] = [
{
name:"password",
description:"Set a unique password to protect the account",
children:<Button className='security_setting_button'>تغيير كلمة المرور</Button>,
},
{
name:"two_factors",
description:"Receive codes via SMS or email every time you log in",
// children:<Button className='button'> change</Button>,
},
{
name:"verify_phone_number",
description:"The phone number associated with the account",
// children:<Button className='button'> change</Button>,
},
{
name:"email_address",
description:"The email address associated with the account",
// children:<Button className='button'> change</Button>,
},
{
name:"device_management",
description:"Devices associated with the account",
children:<Button className='security_setting_button'>إدارة</Button>,
},
{
name:"account_activity",
description:"account_activities",
children:<Button className='security_setting_button'>عرض</Button>,
},
{
name:"deactivate_the_account",
description:"This will close your account. Your account will be interactive when you log in again",
children:<Button className='security_setting_button'>الغاء تنشيط </Button>,
},
{
name:"delete_account",
description:"Your account will be permanently deleted",
children:<Button className='security_setting_button security_setting_button_danger'>حذف</Button>,
},
]

View File

@ -0,0 +1,51 @@
import React, { useState } from 'react';
import type { TabsProps } from 'antd';
import { Tabs } from 'antd';
import { useTranslation } from 'react-i18next';
import { CgProfile } from "react-icons/cg";
import { useWindowResize } from '../../../../Hooks/useWindowResize';
import Card from '../../../ReSeller/Notifications/Card';
import FileSetting from './FileSetting';
import SecuritySetting from './SecuritySetting';
import Notification from './Notification';
type TabPosition = 'left' | 'right' | 'top' | 'bottom';
const SettingTabs: React.FC = () => {
const {windowWidth} = useWindowResize()
const {t} = useTranslation();
const [tabPosition, setTabPosition] = useState<TabPosition>(windowWidth < 800 ? 'top' : 'left');
const items: TabsProps['items'] = [
{
key: '1',
label: t('table.file_setting'),
children: <FileSetting />,
},
{
key: '2',
label: t('table.security_setting'),
children: <SecuritySetting/>,
},
{
key: '3',
label: t('table.notification'),
children: <Notification/>,
},
];
return (
<>
<Tabs
tabPosition={tabPosition}
addIcon
items={items}
className='setting_tabs'
defaultActiveKey='1'
/>
</>
);
};
export default SettingTabs;

View File

@ -0,0 +1,29 @@
import { ReactElement } from 'react';
import { useTranslation } from 'react-i18next'
const TabHeader = ({
name,
description,
children
}:{
name:string,
description:string,
children?:ReactElement
}) => {
const {t} = useTranslation();
return (
<div className='setting_tab_header'>
<div>
<h5>{t(`table.${name}`)}</h5>
<p>{t(`table.${description}`)}</p>
</div>
<div>
{children}
</div>
</div>
)
}
export default TabHeader

View File

@ -0,0 +1,31 @@
import { FaPlus } from "react-icons/fa";
import useModalHandler from "../../../utils/useModalHandler";
import { ModalEnum } from "../../../enums/Model";
import { useTranslation } from "react-i18next";
import { lazy, Suspense } from "react";
import { Spin } from "antd";
import useSetPageTitle from "../../../Hooks/useSetPageTitle";
import PageHeader from "../../../Layout/Dashboard/PageHeader";
import SettingTabs from "./Form/SettingTabs";
const TableHeader = () => {
const [t] = useTranslation();
useSetPageTitle([
{name:`${t(`page_header.home`)}`, path:"/"},
{name:`${t(`page_header.setting`)}`, path:"setting"}
]);
return (
<div className="TableWithHeader">
<Suspense fallback={<Spin />}>
<PageHeader
pageTitle="setting"
/>
<SettingTabs/>
</Suspense>
</div>
);
};
export default TableHeader;

View File

@ -18,24 +18,43 @@ const PersonalDetailsForm = () => {
</header> </header>
<main className="main_form_body"> <main className="main_form_body">
<ValidationField <ValidationField
name={"first_name"} name={"id_number"}
placeholder={"_"} placeholder={"_"}
label={"first_name"} label={"ID Number"}
/> />
<ValidationField <ValidationField
name={"last_name"} name={"addition_date"}
placeholder={"_"} placeholder={"_"}
type="Date" type="Date"
label={"last_name"} label={"Addition Date"}
/> />
<ValidationField <ValidationField
name={"email_address"} name={"status"}
placeholder={"_"} placeholder={"_"}
label={"email_address"} label={"status"}
type="Select" type="Select"
option={statusType} option={statusType}
/> />
<ValidationField
name={"full_name"}
placeholder={"_"}
label={"Full Name"}
/>
<ValidationField
name={"phone_number"}
placeholder={"_"}
label={"phone_number"}
/>
<ValidationField
name={"mobile_number"}
placeholder={"_"}
label={"Mobile Number"}
/>
<ValidationField <ValidationField
name={"username"} name={"username"}
placeholder={"_"} placeholder={"_"}
@ -43,11 +62,10 @@ const PersonalDetailsForm = () => {
/> />
<ValidationField <ValidationField
name={"full_name"} name={"seller_percentage"}
placeholder={"_"} placeholder={"_"}
label={"Phone Number"} label={"Seller Percentage"}
/> />
</main> </main>
</div> </div>
); );

View File

@ -37,10 +37,11 @@ const User = React.lazy(() => import("./Pages/Admin/User/Page"));
const QuestionBank = React.lazy(() => import("./Pages/Admin/QuestionBank/Page")); const QuestionBank = React.lazy(() => import("./Pages/Admin/QuestionBank/Page"));
const Notifications = React.lazy(() => import("./Pages/Admin/Notifications/Page")); const Notifications = React.lazy(() => import("./Pages/Admin/Notifications/Page"));
const Profile = React.lazy(() => import("./Pages/Admin/Profile/Page")); const Profile = React.lazy(() => import("./Pages/Admin/Profile/Page"));
const Setting = React.lazy(() => import("./Pages/Admin/Setting/Page"));
const Roles = React.lazy(() => import("./Pages/Admin/Roles/Page"));
const Permissions = React.lazy(() => import("./Pages/Admin/Roles/Permissions/Page")); const Permissions = React.lazy(() => import("./Pages/Admin/Roles/Permissions/Page"));
const Roles = React.lazy(() => import("./Pages/Admin/Roles/Page"));
const Report = React.lazy(() => import("./Pages/Admin/Report/Page")); const Report = React.lazy(() => import("./Pages/Admin/Report/Page"));
const Param = React.lazy(() => import("./Pages/Admin/Param/Page")); const Param = React.lazy(() => import("./Pages/Admin/Param/Page"));
@ -205,7 +206,7 @@ export const menuItems: TMenuItem[] = [
element: <ProfileReSeller />, element: <ProfileReSeller />,
icon: <FaSellcast />, icon: <FaSellcast />,
text: "sidebar.profile", text: "sidebar.profile",
path: `//${ABILITIES_ENUM?.PROFILE}`, path: `/${ABILITIES_ENUM?.PROFILE}`,
abilities: ABILITIES_ENUM?.Profile_RE_SELLER, abilities: ABILITIES_ENUM?.Profile_RE_SELLER,
abilities_value: ABILITIES_VALUES_ENUM.INDEX, abilities_value: ABILITIES_VALUES_ENUM.INDEX,
prevPath: 0, prevPath: 0,
@ -338,6 +339,14 @@ export const CrudRoute: TCrudRoute[] = [
abilities_value: ABILITIES_VALUES_ENUM.INDEX, abilities_value: ABILITIES_VALUES_ENUM.INDEX,
prevPath: 0, prevPath: 0,
}, },
{
header: "page_header.setting",
element: <Setting />,
path: `/${ABILITIES_ENUM?.SETTING}`,
abilities: ABILITIES_ENUM?.SETTING,
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
prevPath: 0,
},
//// RE_SELLER //// RE_SELLER
{ {
header: "page_header.notifications", header: "page_header.notifications",

View File

@ -13,4 +13,5 @@
@import './InfoCard.scss'; @import './InfoCard.scss';
@import './notifications.scss'; @import './notifications.scss';
@import './profile.scss'; @import './profile.scss';
@import './collections.scss' @import './collections.scss';
@import './setting.scss';

View File

@ -4,6 +4,13 @@
gap: 20px; gap: 20px;
background: var(--bg); background: var(--bg);
padding: 40px 10px; padding: 40px 10px;
.ValidationField{
label{
font-weight: 600;
font-size: 16px !important;
color: var(--secondary) !important;
}
}
> * { > * {
// max-width: 30%; // max-width: 30%;
flex-basis: 31%; flex-basis: 31%;
@ -21,7 +28,7 @@
} }
} }
.resellerButton { .resellerButton,.file_setting_buttons {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: flex-end; justify-content: flex-end;

View File

@ -0,0 +1,153 @@
.setting_tabs {
border-top: 1px solid var(--border-color-2);
.ant-tabs-nav {
width: 20%;
}
.ant-tabs-nav-list {
width: 100% !important;
border-left: 1px solid var(--border-color-2);
padding-left: 20px;
}
.ant-tabs-tab {
margin-top: 10px;
color: var(--secondary);
}
.ant-tabs-tab-active {
background: #3D5EE11A !important;
border-radius: 8px 0 0 8px;
border-right: 1px solid #3D5EE11A;
margin-left: 0 !important;
}
.ant-tabs-content-holder {
padding: 20px 0 !important;
}
.ant-tabs-content-holder {
border: none;
margin-right: 20px;
padding-top: 20px !important;
padding-left: 0 !important;
}
.ant-tabs-tabpane-active {
padding-left: 0 !important;
}
.notification {
.setting_notification_body {
padding: 10px 20px;
box-shadow: 0px 0px 32px 0px #080F3414;
border: 1.5px solid #E9EDF4;
border-radius: 10px;
background: #fff;
}
}
}
.setting_tab_header,
.notification_card,
.security_card {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid var(--border-color-2);
padding-block: 10px 20px;
div {
display: flex;
flex-direction: column;
gap: 10px;
h5 {
color: var(--secondary);
font-size: 1.4vw;
}
p {
font-size: 1.1vw;
color: var(--value);
}
.file_setting_buttons {
display: flex !important;
flex-direction: row;
}
}
}
.setting_tab_header {
width: 100%;
margin-bottom: 30px;
}
.notification_card{
&:nth-last-child(1) {
border: none;
}
h5 {
font-size: 1.2vw !important;
}
p {
font-size: .9vw !important;
}
.ant-form-item,
.ant-form-item-control-input-content {
height: 3vh;
gap: 0 !important;
margin-bottom: 0 !important;
}
.ant-checkbox .ant-checkbox-inner {
width: 25px;
height: 25px;
border: 2px solid var(--border-color-2);
}
}
.security_card{
padding: 20px 20px;
box-shadow: 0px 0px 32px 0px #080F3414;
border: 1.5px solid #E9EDF4;
border-radius: 10px;
background: #fff;
margin-block: 20px ;
h5 {
font-size: 1.2vw !important;
}
p {
font-size: .9vw !important;
}
}
.security_setting_button{
display: flex;
align-items: center;
justify-content: center;
outline: none;
border: 2px solid var(--primary);
border-radius: 7px;
padding: 22px 15px !important;
color: var(--primary);
gap: 5px;
&:hover{
border: 2px solid var(--primary) !important;
background: var(--primary) !important;
color: var(--white) !important;
}
}
.security_setting_button_danger{
border-color:var(--warning);
color: var(--warning);
&:hover{
border: 2px solid var(--warning) !important;
background: var(--warning) !important;
}
}

View File

@ -55,7 +55,8 @@ export enum ABILITIES_ENUM {
NOTIFICATIONS_RE_SELLER = "notification_re_seller" , NOTIFICATIONS_RE_SELLER = "notification_re_seller" ,
Profile_RE_SELLER = "profile_re_seller" , Profile_RE_SELLER = "profile_re_seller" ,
Sales = "sales", Sales = "sales",
Collections = "collections" Collections = "collections",
SETTING = "setting"
//// ////
} }

View File

@ -5,3 +5,13 @@ export const CollectionData = [
{label:"تم تحصيله",value:"2.000.000"}, {label:"تم تحصيله",value:"2.000.000"},
{label:"المتبقي",value:"2.000.000"}, {label:"المتبقي",value:"2.000.000"},
] ]
export const NotificationData = [
{label:"إشعارات البريد الإلكتروني",value:"يمكن أن ترسل لك Substance إشعارات عبر البريد الإلكتروني لأي رسائل مباشرة جديدة"},
{label:"إشعارات البريد الإلكتروني",value:"يمكن أن ترسل لك Substance إشعارات عبر البريد الإلكتروني لأي رسائل مباشرة جديدة"},
{label:"إشعارات البريد الإلكتروني",value:"يمكن أن ترسل لك Substance إشعارات عبر البريد الإلكتروني لأي رسائل مباشرة جديدة"},
{label:"إشعارات البريد الإلكتروني",value:"يمكن أن ترسل لك Substance إشعارات عبر البريد الإلكتروني لأي رسائل مباشرة جديدة"},
{label:"إشعارات البريد الإلكتروني",value:"يمكن أن ترسل لك Substance إشعارات عبر البريد الإلكتروني لأي رسائل مباشرة جديدة"},
]

View File

@ -141,7 +141,8 @@
"managers":"مدراء", "managers":"مدراء",
"sales":"المبيعات", "sales":"المبيعات",
"hide_hint":"اخفاء الشرح", "hide_hint":"اخفاء الشرح",
"show_hint":"عرض الشرح" "show_hint":"عرض الشرح",
"setting":"الإعدادات"
}, },
"columns": { "columns": {
"id": "الرقم التعريفي", "id": "الرقم التعريفي",
@ -283,7 +284,23 @@
"sorry_something_went_wrong": "عفوا ، حدث خطأ ما", "sorry_something_went_wrong": "عفوا ، حدث خطأ ما",
"error_404_Page_not_found._Sorry,_the_page_you_are_looking_for_does_not_exist": "خطأ 404 لم يتم العثور على الصفحة. عذرا الصفحة التي تبحث عنها غير موجودة ", "error_404_Page_not_found._Sorry,_the_page_you_are_looking_for_does_not_exist": "خطأ 404 لم يتم العثور على الصفحة. عذرا الصفحة التي تبحث عنها غير موجودة ",
"return_to_the_dashboard": "العودة إلى لوحة القيادة", "return_to_the_dashboard": "العودة إلى لوحة القيادة",
"save_changes":"حفظ التغييرات" "save_changes":"حفظ التغييرات",
"password":"كلمة المرور",
"two_factors":"عاملان",
"verify_phone_number":"التحقق من رقم الهاتف",
"email_address":"عنوان البريد الإلكتروني",
"device_management":"إدارة الأجهزة",
"account_activity":"نشاط الحساب",
"deactivate_the_account":"إلغاء تنشيط الحساب",
"delete_account":"حذف الحساب",
"Set a unique password to protect the account":"تعيين كلمة مرور فريدة لحماية الحساب",
"Receive codes via SMS or email every time you log in":"تلقي الرموز عبر الرسائل القصيرة أو البريد الإلكتروني في كل مرة تقوم فيها بتسجيل الدخول",
"The phone number associated with the account":"رقم الهاتف المرتبط بالحساب",
"The email address associated with the account":"عنوان البريد الإلكتروني المرتبط بالحساب",
"Devices associated with the account":"الأجهزة المرتبطة بالحساب",
"account_activities":"أنشطة الحساب",
"This will close your account. Your account will be interactive when you log in again":"سيؤدي هذا إلى إغلاق حسابك. سيكون حسابك تفاعليا عند تسجيل الدخول مرة أخرى",
"Your account will be permanently deleted":"سيتم حذف حسابك نهائيا"
}, },
"Table": { "Table": {
"header": "", "header": "",
@ -870,7 +887,8 @@
"add_manager":"إضافة مدير", "add_manager":"إضافة مدير",
"collections": "التحصيلات", "collections": "التحصيلات",
"sales":"المبيعات", "sales":"المبيعات",
"edit_manager":"تعديل مدير" "edit_manager":"تعديل مدير",
"setting":"الإعدادات"
}, },
"page_header": { "page_header": {
"home": "لوحة القيادة", "home": "لوحة القيادة",
@ -916,7 +934,8 @@
"permissions":"اذونات", "permissions":"اذونات",
"managers":"مدراء", "managers":"مدراء",
"collections": "التحصيلات", "collections": "التحصيلات",
"sales":"المبيعات" "sales":"المبيعات",
"setting":"الإعدادات"
}, },
"table": { "table": {
"student": "قائمة الطلاب", "student": "قائمة الطلاب",
@ -927,7 +946,13 @@
"managers":"مدراء", "managers":"مدراء",
"managers_list":"قائمة المدراء", "managers_list":"قائمة المدراء",
"sales":"المبيعات", "sales":"المبيعات",
"collections": "التحصيلات" "collections": "التحصيلات",
"setting":"الإعدادات",
"file_setting":"إعدادات الملف",
"security_setting":"إعدادات الأمان",
"notification":"الاشعارات",
"upload_your_photo_and_personal_data_here":"قم بتحميل صورتك وبياناتك الشخصية هنا",
"get_notified_of_whats_happening_now_you_can_turn_it_off_at_any_time":"احصل على إشعار بما يحدث الآن ، يمكنك إيقاف تشغيله في أي وقت"
}, },
"alphabet": { "alphabet": {
"A": "A", "A": "A",

7
src/types/Setting.ts Normal file
View File

@ -0,0 +1,7 @@
import { ReactElement } from "react";
export type SettingType = {
name:string;
description:string;
children?:ReactElement;
}