parent
98b14196a4
commit
613b6156f2
17 changed files with 595 additions and 50 deletions
@ -0,0 +1,68 @@ |
|||||||
|
import React from "react"; |
||||||
|
import { useState } from "react"; |
||||||
|
import { Link } from "react-router-dom"; |
||||||
|
|
||||||
|
let data = [ |
||||||
|
{ |
||||||
|
name: "داشبورد", |
||||||
|
link: "/", |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: "مدارس", |
||||||
|
link: "schools", |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: "محصولات", |
||||||
|
link: "products", |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: "کد تخفیف", |
||||||
|
link: "discount_codes", |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: "اضافه کردن آزمون", |
||||||
|
link: "add-exam", |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: "خروج", |
||||||
|
link: "#", |
||||||
|
}, |
||||||
|
]; |
||||||
|
|
||||||
|
let location = window.location.pathname; |
||||||
|
let intial = 0; |
||||||
|
if (location.includes("schools")) { |
||||||
|
intial = 1; |
||||||
|
} else if (location.includes("products")) { |
||||||
|
intial = 2; |
||||||
|
} else if (location.includes("discount_codes")) { |
||||||
|
intial = 3; |
||||||
|
} else if (location.includes("add-exam")) { |
||||||
|
intial = 4; |
||||||
|
} |
||||||
|
const AdminNav = () => { |
||||||
|
const [activeNav, setActiveNav] = useState(intial); |
||||||
|
const changeNav = (index) => { |
||||||
|
setActiveNav(index); |
||||||
|
}; |
||||||
|
return ( |
||||||
|
<div className="w-[120px] h-screen fixed flex flex-col top-0 right-0 bg-white z-[10] border-l border-[#e5e5e5]"> |
||||||
|
{data?.map((item, index) => ( |
||||||
|
<Link |
||||||
|
to={`/adminpanel/${item.link}`} |
||||||
|
className="w-full flex-1 flex items-center justify-center text-sm cursor-pointer" |
||||||
|
style={ |
||||||
|
index === activeNav |
||||||
|
? { backgroundColor: "#df1452", color: "#fff" } |
||||||
|
: null |
||||||
|
} |
||||||
|
onClick={() => changeNav(index)} |
||||||
|
> |
||||||
|
{item?.name} |
||||||
|
</Link> |
||||||
|
))} |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
export default AdminNav; |
@ -0,0 +1,105 @@ |
|||||||
|
|
||||||
|
|
||||||
|
import React, { useMemo, useState } from "react"; |
||||||
|
import { useEffect } from "react"; |
||||||
|
import { connect } from "react-redux"; |
||||||
|
import Table from "../../components/Table"; |
||||||
|
import * as actions from "../../redux/actions"; |
||||||
|
import Editor from "./layouts/Editor"; |
||||||
|
|
||||||
|
const source = "book"; |
||||||
|
const title = " مدیریت کاربران"; |
||||||
|
|
||||||
|
const SchoolMangement = ({ |
||||||
|
info, |
||||||
|
getData, |
||||||
|
tabs, |
||||||
|
setTabs, |
||||||
|
add, |
||||||
|
update, |
||||||
|
getSchoolList, |
||||||
|
schoolList, |
||||||
|
schoolUserList, |
||||||
|
schema, |
||||||
|
}) => { |
||||||
|
useMemo(() => { |
||||||
|
// getData({ num: 1000 });
|
||||||
|
getSchoolList(); |
||||||
|
}, []); |
||||||
|
// console.log(info);
|
||||||
|
console.log("SchoolManagement render---------------------------------"); |
||||||
|
console.log(schoolList); |
||||||
|
console.log(schema); |
||||||
|
console.log(info); |
||||||
|
// console.log("==============^tabs^==============");
|
||||||
|
// console.log(tabs);
|
||||||
|
useEffect(() => { |
||||||
|
setTabs([ |
||||||
|
{ |
||||||
|
id: 0, |
||||||
|
name: title, |
||||||
|
isActive: true, |
||||||
|
element: "table", |
||||||
|
}, |
||||||
|
]); |
||||||
|
}, []); |
||||||
|
// console.log(tabs);
|
||||||
|
// const [tabs, setTabs] = useState([
|
||||||
|
// {
|
||||||
|
// id: 0,
|
||||||
|
// name: title,
|
||||||
|
// isActive: true,
|
||||||
|
// },
|
||||||
|
// ]);
|
||||||
|
const [activeOtherTab, setActiveOtherTab] = useState(false); |
||||||
|
const [fake, setFake] = useState(0); |
||||||
|
const [schoolId, setSchoolId] = useState(null); |
||||||
|
const [setp, setStep] = useState(1); |
||||||
|
|
||||||
|
const submitHandler = () => { |
||||||
|
getData({ id: schoolId }); |
||||||
|
setStep(2); |
||||||
|
}; |
||||||
|
return ( |
||||||
|
<div |
||||||
|
className="UserManagement w-[95.5%] h-screen max-h-screen bg-[#F8F8F8] overflow-y-auto rtl relative" |
||||||
|
// style={{ width: "calc(100% - 4.5%)" }}
|
||||||
|
> |
||||||
|
<div className="flex flex-1 w-full pt-12 pb-4"> |
||||||
|
<Table |
||||||
|
data={schoolList || []} |
||||||
|
schema={schema || []} |
||||||
|
Editor={Editor} |
||||||
|
add={add} |
||||||
|
update={update} |
||||||
|
getData={getData} |
||||||
|
title={title} |
||||||
|
tabs={tabs} |
||||||
|
setTabs={setTabs} |
||||||
|
fake={fake} |
||||||
|
setFake={setFake} |
||||||
|
activeOtherTab={activeOtherTab} |
||||||
|
setActiveOtherTab={setActiveOtherTab} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
||||||
|
const mapStateToProps = (state) => ({ |
||||||
|
info: state[source], |
||||||
|
tabs: state.table.tabs, |
||||||
|
schoolList: state.book.schoolList, |
||||||
|
schoolUserList: state.book.schoolUserList, |
||||||
|
schema:state.book.schema |
||||||
|
}); |
||||||
|
|
||||||
|
const mapDispatchToProps = { |
||||||
|
// getData: actions[source].list,
|
||||||
|
getData: actions[source].schoolUser, |
||||||
|
setTabs: actions.table.setTab, |
||||||
|
update: actions[source].update, |
||||||
|
add: actions[source].add, |
||||||
|
getSchoolList: actions.book.schoolList, |
||||||
|
}; |
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(SchoolMangement); |
@ -0,0 +1,202 @@ |
|||||||
|
import React, { useEffect, useState } from "react"; |
||||||
|
import { connect } from "react-redux"; |
||||||
|
import { file } from "../../../redux/actions"; |
||||||
|
import loadingGiff from "../../../assets/img/Rolling-1s-200px.gif"; |
||||||
|
import SimpleDatePicker from "../../../components/SimpleDatePicker"; |
||||||
|
import moment from "jalali-moment"; |
||||||
|
const baseUrl = "https://light.barnamenegar.com/api/v1"; |
||||||
|
const components = (props) => ({ |
||||||
|
text: ( |
||||||
|
<input |
||||||
|
type="text" |
||||||
|
className="table-edit-input w-full py-3 px-2 rounded-md border border-[#D5DEEA]" |
||||||
|
{...props} |
||||||
|
/> |
||||||
|
), |
||||||
|
string: ( |
||||||
|
<textarea |
||||||
|
type="text" |
||||||
|
className="table-edit-input w-full py-3 px-2 rounded-md border border-[#D5DEEA]" |
||||||
|
{...props} |
||||||
|
/> |
||||||
|
), |
||||||
|
number: ( |
||||||
|
<input |
||||||
|
type="number" |
||||||
|
className="table-edit-input w-full py-3 px-2 rounded-md border border-[#D5DEEA]" |
||||||
|
{...props} |
||||||
|
/> |
||||||
|
), |
||||||
|
select: ( |
||||||
|
<select |
||||||
|
type="text" |
||||||
|
className="table-edit-input w-full py-3 px-2 rounded-md border border-[#D5DEEA]" |
||||||
|
{...props} |
||||||
|
> |
||||||
|
{Object.entries(props?.options || {}).map(([v, k]) => ( |
||||||
|
<option value={v} key={v}> |
||||||
|
{k} |
||||||
|
</option> |
||||||
|
))} |
||||||
|
</select> |
||||||
|
), |
||||||
|
file: ( |
||||||
|
<div className="table-edit-input w-full py-3 px-2 rounded-md border border-[#D5DEEA] flex justify-between bg-[#fff]"> |
||||||
|
<div className="w-full flex items-center"> |
||||||
|
<div |
||||||
|
className="w-fit w-24 text-center py-1 rounded bg-[#111] text-white text-sm cursor-pointer" |
||||||
|
onClick={props.chooseFile} |
||||||
|
> |
||||||
|
انتخاب فایل |
||||||
|
</div> |
||||||
|
{/* <div className="text-xs mt-2 text-right">{props.fileNmae}</div> */} |
||||||
|
{props.fileNmae && !props.loading && ( |
||||||
|
<div |
||||||
|
className="w-fit w-24 py-1 rounded bg-[#65A9FF] text-white text-sm mr-2 cursor-pointer" |
||||||
|
onClick={props.uploadHandler} |
||||||
|
> |
||||||
|
آپلود |
||||||
|
</div> |
||||||
|
)} |
||||||
|
{props.loading && ( |
||||||
|
<img src={loadingGiff} alt="loadingGiff" className="h-10 mr-2" /> |
||||||
|
)} |
||||||
|
<input |
||||||
|
className="edit-file-input w-0 h-0 hidden" |
||||||
|
id="edit-file-input" |
||||||
|
type={"file"} |
||||||
|
// onChange={(e) => {
|
||||||
|
// props.setFileName(e.target.value);
|
||||||
|
// }}
|
||||||
|
onChange={(e) => props.fileInputHandler(e)} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
{props.defaultValue && !props?.fileNmae ? ( |
||||||
|
<img |
||||||
|
src={baseUrl + "/file/" + props.defaultValue} |
||||||
|
className="edit-file-img-placeholder h-10" |
||||||
|
/> |
||||||
|
) : null} |
||||||
|
{props?.fileNmae && ( |
||||||
|
<img src={props?.fileNmae} className="edit-file-img-placeholder h-10" /> |
||||||
|
)} |
||||||
|
</div> |
||||||
|
), |
||||||
|
date: ( |
||||||
|
<div className="w-full"> |
||||||
|
<SimpleDatePicker returnValue={props.setDateInfo} mode={props.mode} /> |
||||||
|
</div> |
||||||
|
), |
||||||
|
}); |
||||||
|
|
||||||
|
const Filed = (props) => { |
||||||
|
return components(props)[props.type] || <div>{props.type}</div>; |
||||||
|
}; |
||||||
|
const Editor = ({ data, schema, update, add, loading,lastUpload,uploadFile }) => { |
||||||
|
const [info, setInfo] = useState(data ? { id: data?.original?.id } : {}); |
||||||
|
const changeInputHandler = (e, key) => { |
||||||
|
setInfo({ ...info, [key]: e.target.value }); |
||||||
|
}; |
||||||
|
useEffect(() => { |
||||||
|
if (lastUpload) { |
||||||
|
setInfo({ ...info, fileId: String(lastUpload) }); |
||||||
|
} |
||||||
|
}, [lastUpload]); |
||||||
|
|
||||||
|
const submitHandler = () => { |
||||||
|
if (data) update(info); |
||||||
|
else add(info); |
||||||
|
console.log(info); |
||||||
|
}; |
||||||
|
|
||||||
|
const [fileNmae, setFileName] = useState(null); |
||||||
|
const chooseFile = () => { |
||||||
|
document.querySelector(".edit-file-input").click(); |
||||||
|
}; |
||||||
|
const fileInputHandler = (e) => { |
||||||
|
console.log(e.target.value); |
||||||
|
if (e.target.files && e.target.files[0]) { |
||||||
|
var reader = new FileReader(); |
||||||
|
|
||||||
|
reader.onload = function (event) { |
||||||
|
setFileName(event.target.result); |
||||||
|
}; |
||||||
|
|
||||||
|
reader.readAsDataURL(e.target.files[0]); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
const uploadHandler=()=>{ |
||||||
|
uploadFile({ |
||||||
|
file: document.querySelector("#edit-file-input").files[0], |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
const [dateInfo,setDateInfo]=useState(null); |
||||||
|
const datehandler=(value,mode)=>{ |
||||||
|
setDateInfo({ ...value,mode}); |
||||||
|
} |
||||||
|
useEffect(() => { |
||||||
|
console.log("::::::::::::::::::::::::::::::::::::::::::::-") |
||||||
|
console.log(dateInfo); |
||||||
|
if(dateInfo?.day){ |
||||||
|
setInfo({ |
||||||
|
...info, |
||||||
|
[dateInfo.mode]: moment( |
||||||
|
`${dateInfo?.year}/${dateInfo?.month}/${dateInfo?.day}` |
||||||
|
) |
||||||
|
.locale("en") |
||||||
|
.format("YYYY-MM-DD"), |
||||||
|
}); |
||||||
|
} |
||||||
|
}, [dateInfo]); |
||||||
|
return ( |
||||||
|
<div className="w-full py-3" key={data?.id || 0}> |
||||||
|
{console.log({ data })} |
||||||
|
<div className="w-full flex rtl flex-wrap items-center justify-between gap-y-6"> |
||||||
|
{schema?.map((item, index) => ( |
||||||
|
<div key={index} className="w-1/2 shrink-0 flex items-center "> |
||||||
|
<div className="w-1/6 text-sm ml-2">{item?.description}:</div> |
||||||
|
<Filed |
||||||
|
type={ |
||||||
|
item?.options |
||||||
|
? "select" |
||||||
|
: item.name == "fileId" |
||||||
|
? "file" |
||||||
|
: item?.type |
||||||
|
} |
||||||
|
options={item?.options} |
||||||
|
defaultValue={data?.original[item?.name]} |
||||||
|
onChange={(e) => changeInputHandler(e, item?.name)} |
||||||
|
fileNmae={fileNmae} |
||||||
|
setFileName={setFileName} |
||||||
|
chooseFile={chooseFile} |
||||||
|
fileInputHandler={fileInputHandler} |
||||||
|
uploadHandler={uploadHandler} |
||||||
|
loading={loading} |
||||||
|
setDateInfo={datehandler} |
||||||
|
mode={item?.name} |
||||||
|
/> |
||||||
|
</div> |
||||||
|
))} |
||||||
|
</div> |
||||||
|
<div |
||||||
|
className="px-6 py-4 w-fit rounded-md bg-[#df1452] text-[#fff] text-base cursor-pointer mx-auto mt-6" |
||||||
|
onClick={submitHandler} |
||||||
|
> |
||||||
|
{data ? "ثبت تغییرات" : "ثبت ردیف"} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
const mapStateToProps = (state) => ({ |
||||||
|
loading: state.file.loading, |
||||||
|
lastUpload: state.file.lastUpload, |
||||||
|
}); |
||||||
|
|
||||||
|
const mapDispatchToProps = { |
||||||
|
uploadFile : file.upload |
||||||
|
}; |
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(Editor); |
Loading…
Reference in new issue