settings
This commit is contained in:
parent
3a877b5053
commit
e0e2839cf3
20
src/Hooks/useWindowResize.tsx
Normal file
20
src/Hooks/useWindowResize.tsx
Normal 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};
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ const SideBar = ({
|
|||
</div>
|
||||
<div className="side_bar_setting">
|
||||
<p>{t("sidebar.setting")}</p>
|
||||
<div>
|
||||
<div onClick={() => {navigate("/setting")}}>
|
||||
<CiSettings />
|
||||
<span>{t("sidebar.setting")}</span>
|
||||
</div>
|
||||
|
|
|
|||
42
src/Pages/Admin/Setting/Form/FileSetting.tsx
Normal file
42
src/Pages/Admin/Setting/Form/FileSetting.tsx
Normal 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
|
||||
23
src/Pages/Admin/Setting/Form/FileSetting/AttachmentForm.tsx
Normal file
23
src/Pages/Admin/Setting/Form/FileSetting/AttachmentForm.tsx
Normal 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;
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
|
|
@ -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);
|
||||
};
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
13
src/Pages/Admin/Setting/Form/FileSetting/formUtils.ts
Normal file
13
src/Pages/Admin/Setting/Form/FileSetting/formUtils.ts
Normal 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({});
|
||||
};
|
||||
36
src/Pages/Admin/Setting/Form/Notification.tsx
Normal file
36
src/Pages/Admin/Setting/Form/Notification.tsx
Normal 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
|
||||
|
|
@ -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
|
||||
13
src/Pages/Admin/Setting/Form/Notification/formUtils.ts
Normal file
13
src/Pages/Admin/Setting/Form/Notification/formUtils.ts
Normal 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({});
|
||||
};
|
||||
29
src/Pages/Admin/Setting/Form/SecuritySetting.tsx
Normal file
29
src/Pages/Admin/Setting/Form/SecuritySetting.tsx
Normal 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
|
||||
|
|
@ -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
|
||||
|
|
@ -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>,
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
51
src/Pages/Admin/Setting/Form/SettingTabs.tsx
Normal file
51
src/Pages/Admin/Setting/Form/SettingTabs.tsx
Normal 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;
|
||||
29
src/Pages/Admin/Setting/Form/TabHeader.tsx
Normal file
29
src/Pages/Admin/Setting/Form/TabHeader.tsx
Normal 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
|
||||
31
src/Pages/Admin/Setting/Page.tsx
Normal file
31
src/Pages/Admin/Setting/Page.tsx
Normal 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;
|
||||
|
|
@ -18,24 +18,43 @@ const PersonalDetailsForm = () => {
|
|||
</header>
|
||||
<main className="main_form_body">
|
||||
<ValidationField
|
||||
name={"first_name"}
|
||||
name={"id_number"}
|
||||
placeholder={"_"}
|
||||
label={"first_name"}
|
||||
label={"ID Number"}
|
||||
/>
|
||||
<ValidationField
|
||||
name={"last_name"}
|
||||
name={"addition_date"}
|
||||
placeholder={"_"}
|
||||
type="Date"
|
||||
label={"last_name"}
|
||||
label={"Addition Date"}
|
||||
/>
|
||||
|
||||
<ValidationField
|
||||
name={"email_address"}
|
||||
name={"status"}
|
||||
placeholder={"_"}
|
||||
label={"email_address"}
|
||||
label={"status"}
|
||||
type="Select"
|
||||
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
|
||||
name={"username"}
|
||||
placeholder={"_"}
|
||||
|
|
@ -43,11 +62,10 @@ const PersonalDetailsForm = () => {
|
|||
/>
|
||||
|
||||
<ValidationField
|
||||
name={"full_name"}
|
||||
name={"seller_percentage"}
|
||||
placeholder={"_"}
|
||||
label={"Phone Number"}
|
||||
label={"Seller Percentage"}
|
||||
/>
|
||||
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -37,10 +37,11 @@ const User = React.lazy(() => import("./Pages/Admin/User/Page"));
|
|||
const QuestionBank = React.lazy(() => import("./Pages/Admin/QuestionBank/Page"));
|
||||
const Notifications = React.lazy(() => import("./Pages/Admin/Notifications/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 Roles = React.lazy(() => import("./Pages/Admin/Roles/Page"));
|
||||
const Report = React.lazy(() => import("./Pages/Admin/Report/Page"));
|
||||
const Param = React.lazy(() => import("./Pages/Admin/Param/Page"));
|
||||
|
||||
|
|
@ -205,7 +206,7 @@ export const menuItems: TMenuItem[] = [
|
|||
element: <ProfileReSeller />,
|
||||
icon: <FaSellcast />,
|
||||
text: "sidebar.profile",
|
||||
path: `//${ABILITIES_ENUM?.PROFILE}`,
|
||||
path: `/${ABILITIES_ENUM?.PROFILE}`,
|
||||
abilities: ABILITIES_ENUM?.Profile_RE_SELLER,
|
||||
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||
prevPath: 0,
|
||||
|
|
@ -338,6 +339,14 @@ export const CrudRoute: TCrudRoute[] = [
|
|||
abilities_value: ABILITIES_VALUES_ENUM.INDEX,
|
||||
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
|
||||
{
|
||||
header: "page_header.notifications",
|
||||
|
|
|
|||
|
|
@ -13,4 +13,5 @@
|
|||
@import './InfoCard.scss';
|
||||
@import './notifications.scss';
|
||||
@import './profile.scss';
|
||||
@import './collections.scss'
|
||||
@import './collections.scss';
|
||||
@import './setting.scss';
|
||||
|
|
|
|||
|
|
@ -4,6 +4,13 @@
|
|||
gap: 20px;
|
||||
background: var(--bg);
|
||||
padding: 40px 10px;
|
||||
.ValidationField{
|
||||
label{
|
||||
font-weight: 600;
|
||||
font-size: 16px !important;
|
||||
color: var(--secondary) !important;
|
||||
}
|
||||
}
|
||||
> * {
|
||||
// max-width: 30%;
|
||||
flex-basis: 31%;
|
||||
|
|
@ -21,7 +28,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
.resellerButton {
|
||||
.resellerButton,.file_setting_buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
|
|
|
|||
153
src/Styles/Pages/setting.scss
Normal file
153
src/Styles/Pages/setting.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -55,7 +55,8 @@ export enum ABILITIES_ENUM {
|
|||
NOTIFICATIONS_RE_SELLER = "notification_re_seller" ,
|
||||
Profile_RE_SELLER = "profile_re_seller" ,
|
||||
Sales = "sales",
|
||||
Collections = "collections"
|
||||
Collections = "collections",
|
||||
SETTING = "setting"
|
||||
|
||||
////
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,4 +4,14 @@ export const CollectionData = [
|
|||
{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 إشعارات عبر البريد الإلكتروني لأي رسائل مباشرة جديدة"},
|
||||
|
||||
]
|
||||
|
|
@ -141,7 +141,8 @@
|
|||
"managers":"مدراء",
|
||||
"sales":"المبيعات",
|
||||
"hide_hint":"اخفاء الشرح",
|
||||
"show_hint":"عرض الشرح"
|
||||
"show_hint":"عرض الشرح",
|
||||
"setting":"الإعدادات"
|
||||
},
|
||||
"columns": {
|
||||
"id": "الرقم التعريفي",
|
||||
|
|
@ -283,7 +284,23 @@
|
|||
"sorry_something_went_wrong": "عفوا ، حدث خطأ ما",
|
||||
"error_404_Page_not_found._Sorry,_the_page_you_are_looking_for_does_not_exist": "خطأ 404 لم يتم العثور على الصفحة. عذرا الصفحة التي تبحث عنها غير موجودة ",
|
||||
"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": {
|
||||
"header": "",
|
||||
|
|
@ -870,7 +887,8 @@
|
|||
"add_manager":"إضافة مدير",
|
||||
"collections": "التحصيلات",
|
||||
"sales":"المبيعات",
|
||||
"edit_manager":"تعديل مدير"
|
||||
"edit_manager":"تعديل مدير",
|
||||
"setting":"الإعدادات"
|
||||
},
|
||||
"page_header": {
|
||||
"home": "لوحة القيادة",
|
||||
|
|
@ -916,7 +934,8 @@
|
|||
"permissions":"اذونات",
|
||||
"managers":"مدراء",
|
||||
"collections": "التحصيلات",
|
||||
"sales":"المبيعات"
|
||||
"sales":"المبيعات",
|
||||
"setting":"الإعدادات"
|
||||
},
|
||||
"table": {
|
||||
"student": "قائمة الطلاب",
|
||||
|
|
@ -927,7 +946,13 @@
|
|||
"managers":"مدراء",
|
||||
"managers_list":"قائمة المدراء",
|
||||
"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": {
|
||||
"A": "A",
|
||||
|
|
|
|||
7
src/types/Setting.ts
Normal file
7
src/types/Setting.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import { ReactElement } from "react";
|
||||
|
||||
export type SettingType = {
|
||||
name:string;
|
||||
description:string;
|
||||
children?:ReactElement;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user