parent
0fe9b16efd
commit
a218d65d93
20 changed files with 1842 additions and 41 deletions
@ -0,0 +1,27 @@ |
|||||||
|
|
||||||
|
|
||||||
|
import proxy from "../proxy"; |
||||||
|
const network = { |
||||||
|
info: |
||||||
|
(data = {}) => |
||||||
|
async (dispatch) => |
||||||
|
await proxy.get("network/info", data, { dispatch }), |
||||||
|
schoolList: |
||||||
|
(data = {}) => |
||||||
|
async (dispatch) => |
||||||
|
await proxy.get("network/schoolList", data, { dispatch }), |
||||||
|
add: |
||||||
|
(data = {}) => |
||||||
|
async (dispatch) => |
||||||
|
await proxy.post("network/add", data, { dispatch }), |
||||||
|
update: |
||||||
|
(data = {}) => |
||||||
|
async (dispatch) => |
||||||
|
await proxy.put("network/update", data, { dispatch }), |
||||||
|
delete: |
||||||
|
(data = {}) => |
||||||
|
async (dispatch) => |
||||||
|
await proxy.delete("network/delete", data, { dispatch }), |
||||||
|
}; |
||||||
|
|
||||||
|
export default network; |
@ -0,0 +1,26 @@ |
|||||||
|
|
||||||
|
import proxy from "../proxy"; |
||||||
|
const offCode = { |
||||||
|
info: |
||||||
|
(data = {}) => |
||||||
|
async (dispatch) => |
||||||
|
await proxy.get("offCode/info", data, { dispatch }), |
||||||
|
schoolList: |
||||||
|
(data = {}) => |
||||||
|
async (dispatch) => |
||||||
|
await proxy.get("offCode/list", data, { dispatch }), |
||||||
|
add: |
||||||
|
(data = {}) => |
||||||
|
async (dispatch) => |
||||||
|
await proxy.post("offCode/add", data, { dispatch }), |
||||||
|
update: |
||||||
|
(data = {}) => |
||||||
|
async (dispatch) => |
||||||
|
await proxy.put("offCode/update", data, { dispatch }), |
||||||
|
delete: |
||||||
|
(data = {}) => |
||||||
|
async (dispatch) => |
||||||
|
await proxy.delete("offCode/delete", data, { dispatch }), |
||||||
|
}; |
||||||
|
|
||||||
|
export default offCode; |
@ -0,0 +1,40 @@ |
|||||||
|
|
||||||
|
|
||||||
|
import { toast } from "react-toastify"; |
||||||
|
|
||||||
|
const initialState = { |
||||||
|
loading: false, |
||||||
|
error: null, |
||||||
|
info: null, |
||||||
|
list: null, |
||||||
|
lastAdd: null, |
||||||
|
schema: [], |
||||||
|
}; |
||||||
|
export default function network(state = initialState, action) { |
||||||
|
let { type, data, schema } = action; |
||||||
|
switch (type) { |
||||||
|
case "network/info": |
||||||
|
return { ...state, loading: false, info: data, error: null }; |
||||||
|
case "network/add": |
||||||
|
toast.success("درخواست با موفقیت انجام شد"); |
||||||
|
return { ...state, loading: false, error: null, lastAdd: data.id }; |
||||||
|
case "network/update": |
||||||
|
toast.success("درخواست با موفقیت انجام شد"); |
||||||
|
return { ...state, loading: false, error: null }; |
||||||
|
case "network/schoolList": |
||||||
|
return { |
||||||
|
...state, |
||||||
|
loading: false, |
||||||
|
error: null, |
||||||
|
list: data, |
||||||
|
schema: schema, |
||||||
|
}; |
||||||
|
case "network/loading": |
||||||
|
return { ...state, loading: true }; |
||||||
|
case "network/error": |
||||||
|
toast.error(data.message); |
||||||
|
return { ...state, loading: false, error: data.message }; |
||||||
|
default: |
||||||
|
return state; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
|
||||||
|
|
||||||
|
import { toast } from "react-toastify"; |
||||||
|
|
||||||
|
const initialState = { |
||||||
|
loading: false, |
||||||
|
error: null, |
||||||
|
info: null, |
||||||
|
list: null, |
||||||
|
lastAdd: null, |
||||||
|
schema: [], |
||||||
|
}; |
||||||
|
export default function offCode(state = initialState, action) { |
||||||
|
let { type, data, schema } = action; |
||||||
|
switch (type) { |
||||||
|
case "offCode/info": |
||||||
|
return { ...state, loading: false, info: data, error: null }; |
||||||
|
case "offCode/add": |
||||||
|
toast.success("درخواست با موفقیت انجام شد"); |
||||||
|
return { ...state, loading: false, error: null, lastAdd: data.id }; |
||||||
|
case "offCode/update": |
||||||
|
toast.success("درخواست با موفقیت انجام شد"); |
||||||
|
return { ...state, loading: false, error: null }; |
||||||
|
case "offCode/list": |
||||||
|
return { |
||||||
|
...state, |
||||||
|
loading: false, |
||||||
|
error: null, |
||||||
|
list: data, |
||||||
|
schema: schema, |
||||||
|
}; |
||||||
|
case "offCode/loading": |
||||||
|
return { ...state, loading: true }; |
||||||
|
case "offCode/error": |
||||||
|
toast.error(data.message); |
||||||
|
return { ...state, loading: false, error: data.message }; |
||||||
|
default: |
||||||
|
return state; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,196 @@ |
|||||||
|
import React, { useEffect } from "react"; |
||||||
|
import { useState } from "react"; |
||||||
|
// import { Document, Page } from "react-pdf";
|
||||||
|
import { Viewer, Worker } from "@react-pdf-viewer/core"; |
||||||
|
import { pageNavigationPlugin } from "@react-pdf-viewer/page-navigation"; |
||||||
|
// Import the styles
|
||||||
|
import "@react-pdf-viewer/core/lib/styles/index.css"; |
||||||
|
import "@react-pdf-viewer/page-navigation/lib/styles/index.css"; |
||||||
|
import { RenderCurrentPageInputProps } from "@react-pdf-viewer/page-navigation"; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const optionNum = ["", "الف", "ب", "پ", "ت", "ث", "ج", "چ", "ح"]; |
||||||
|
|
||||||
|
const NoteContainer = ({ notes, questions, setAnswer, endExam, info }) => { |
||||||
|
const [activeNote, setActiveNote] = useState(0); |
||||||
|
const [activeFileId, setActiveFileId] = useState(null); |
||||||
|
const changeNoteHandler = (index, fileId) => { |
||||||
|
setActiveNote(index); |
||||||
|
setActiveFileId(fileId); |
||||||
|
}; |
||||||
|
|
||||||
|
const [answerList, setAnswerList] = useState([]); |
||||||
|
const [fake, setFake] = useState(0); |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
setActiveFileId(notes[0].fileId); |
||||||
|
let newlist = []; |
||||||
|
for (let i = 0; i < questions?.length; i++) { |
||||||
|
newlist.push(0); |
||||||
|
} |
||||||
|
setAnswerList(newlist); |
||||||
|
}, [notes]); |
||||||
|
|
||||||
|
const chooseOption = (index, answer, id) => { |
||||||
|
let newlist = answerList; |
||||||
|
if (newlist[index] === answer) { |
||||||
|
newlist[index] = 0; |
||||||
|
setAnswer({ |
||||||
|
userAnswerId: id, |
||||||
|
answer: "0", |
||||||
|
}); |
||||||
|
} else { |
||||||
|
newlist[index] = answer; |
||||||
|
setAnswer({ |
||||||
|
userAnswerId: id, |
||||||
|
answer: String(answer), |
||||||
|
}); |
||||||
|
} |
||||||
|
setAnswerList(newlist); |
||||||
|
setFake(Math.random() * 1000); |
||||||
|
}; |
||||||
|
console.log(answerList); |
||||||
|
|
||||||
|
//================================
|
||||||
|
const pageNavigationPluginInstance = pageNavigationPlugin(); |
||||||
|
const { CurrentPageInput } = pageNavigationPluginInstance; |
||||||
|
|
||||||
|
//end exam ============================
|
||||||
|
const endExamHandler = () => { |
||||||
|
endExam({ |
||||||
|
userExamId: info.id, |
||||||
|
}); |
||||||
|
}; |
||||||
|
return ( |
||||||
|
<div className="w-full mt-3 rtl" style={{ height: "calc(100vh - 90px)" }}> |
||||||
|
<div className="w-full h-full flex items-start"> |
||||||
|
{/* -----notes--------- */} |
||||||
|
<div className="flex-1 h-full"> |
||||||
|
<div className="w-full h-10 border flex items-center"> |
||||||
|
{notes?.map((item, index) => ( |
||||||
|
<div |
||||||
|
key={index} |
||||||
|
className="h-full px-3 flex items-center text-sm cursor-pointer" |
||||||
|
style={ |
||||||
|
activeNote === index |
||||||
|
? { backgroundColor: "black", color: "#fff" } |
||||||
|
: null |
||||||
|
} |
||||||
|
onClick={() => changeNoteHandler(index, item.fileId)} |
||||||
|
> |
||||||
|
{item?.name} |
||||||
|
</div> |
||||||
|
))} |
||||||
|
</div> |
||||||
|
|
||||||
|
<div className="w-full flex justify-center mt-2"> |
||||||
|
<div className="w-1/6"> |
||||||
|
<CurrentPageInput /> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
{activeFileId && ( |
||||||
|
<div |
||||||
|
className="pdf-viewer w-full mt-2" |
||||||
|
style={{ height: "calc(100% - 88px)" }} |
||||||
|
> |
||||||
|
<Worker workerUrl="https://unpkg.com/pdfjs-dist@2.13.216/build/pdf.worker.min.js"> |
||||||
|
<Viewer |
||||||
|
fileUrl={`https://api.andishmand.ir/api/v1/file/${activeFileId}`} |
||||||
|
plugins={[pageNavigationPluginInstance]} |
||||||
|
/> |
||||||
|
</Worker> |
||||||
|
</div> |
||||||
|
)} |
||||||
|
</div> |
||||||
|
{/* -----answers----------- */} |
||||||
|
<div className="w-[300px] h-full px-3 overflow-y-auto"> |
||||||
|
<div className="w-full h-10 text-center text-lg">پاسخنامه</div> |
||||||
|
<div className="w-full mt-2"> |
||||||
|
{questions?.map((item, index) => ( |
||||||
|
<div className="w-full flex items-center h-10 mb-2"> |
||||||
|
<div className="w-[40px] h-full bg-[#9999] flex items-center justify-center text-sm rounded-md"> |
||||||
|
{item?.questionNumber} |
||||||
|
</div> |
||||||
|
<div |
||||||
|
className="h-full flex items-center" |
||||||
|
style={{ width: "calc(100% - 40px)" }} |
||||||
|
> |
||||||
|
<div className="flex-1 h-full flex items-center justify-center"> |
||||||
|
<div |
||||||
|
className="w-2/3 h-6 rounded-full border border-[#999] cursor-pointer" |
||||||
|
onClick={() => chooseOption(index, 1, item.id)} |
||||||
|
style={ |
||||||
|
answerList[index] === 1 |
||||||
|
? { backgroundColor: "#5ec427" } |
||||||
|
: null |
||||||
|
} |
||||||
|
></div> |
||||||
|
</div> |
||||||
|
<div className="flex-1 h-full flex items-center justify-center"> |
||||||
|
<div |
||||||
|
className="w-2/3 h-6 rounded-full border border-[#999] cursor-pointer" |
||||||
|
onClick={() => chooseOption(index, 2, item.id)} |
||||||
|
style={ |
||||||
|
answerList[index] === 2 |
||||||
|
? { backgroundColor: "#5ec427" } |
||||||
|
: null |
||||||
|
} |
||||||
|
></div> |
||||||
|
</div> |
||||||
|
{item["question.type"] > 2 && ( |
||||||
|
<div className="flex-1 h-full flex items-center justify-center"> |
||||||
|
<div |
||||||
|
className="w-2/3 h-6 rounded-full border border-[#999] cursor-pointer" |
||||||
|
onClick={() => chooseOption(index, 3, item.id)} |
||||||
|
style={ |
||||||
|
answerList[index] === 3 |
||||||
|
? { backgroundColor: "#5ec427" } |
||||||
|
: null |
||||||
|
} |
||||||
|
></div> |
||||||
|
</div> |
||||||
|
)} |
||||||
|
{item["question.type"] > 3 && ( |
||||||
|
<div className="flex-1 h-full flex items-center justify-center"> |
||||||
|
<div |
||||||
|
className="w-2/3 h-6 rounded-full border border-[#999] cursor-pointer" |
||||||
|
onClick={() => chooseOption(index, 4, item.id)} |
||||||
|
style={ |
||||||
|
answerList[index] === 4 |
||||||
|
? { backgroundColor: "#5ec427" } |
||||||
|
: null |
||||||
|
} |
||||||
|
></div> |
||||||
|
</div> |
||||||
|
)} |
||||||
|
{item["question.type"] > 4 && ( |
||||||
|
<div className="flex-1 h-full flex items-center justify-center"> |
||||||
|
<div |
||||||
|
className="w-2/3 h-6 rounded-full border border-[#999] cursor-pointer" |
||||||
|
onClick={() => chooseOption(index, 5, item.id)} |
||||||
|
style={ |
||||||
|
answerList[index] === 5 |
||||||
|
? { backgroundColor: "#5ec427" } |
||||||
|
: null |
||||||
|
} |
||||||
|
></div> |
||||||
|
</div> |
||||||
|
)} |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
))} |
||||||
|
</div> |
||||||
|
<div |
||||||
|
className="w-full h-10 rounded-full flex items-center justify-center text-center text-sm text-white bg-red52 cursor-pointer mx-auto mt-8" |
||||||
|
onClick={endExamHandler} |
||||||
|
> |
||||||
|
ثبت و اتمام آزمون |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
); |
||||||
|
}; |
||||||
|
|
||||||
|
export default NoteContainer; |
@ -0,0 +1,100 @@ |
|||||||
|
|
||||||
|
|
||||||
|
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 = "offCode"; |
||||||
|
const title = " مدیریت کدهای تخفیف"; |
||||||
|
|
||||||
|
const DisCountCodeManagements = ({ |
||||||
|
info, |
||||||
|
getData, |
||||||
|
tabs, |
||||||
|
setTabs, |
||||||
|
add, |
||||||
|
update, |
||||||
|
CodeList, |
||||||
|
schema, |
||||||
|
}) => { |
||||||
|
useMemo(() => { |
||||||
|
// getData({ num: 1000 });
|
||||||
|
// getSchoolList();
|
||||||
|
getData({ num: 1000 }); |
||||||
|
}, []); |
||||||
|
// console.log(info);
|
||||||
|
console.log("SchoolManagement render---------------------------------"); |
||||||
|
console.log(info); |
||||||
|
console.log(CodeList); |
||||||
|
console.log(schema); |
||||||
|
// 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); |
||||||
|
|
||||||
|
return ( |
||||||
|
<div |
||||||
|
className="UserManagement h-screen max-h-screen bg-[#F8F8F8] overflow-y-auto rtl relative" |
||||||
|
style={{ width: "calc(100vw - 120px)" }} |
||||||
|
> |
||||||
|
<div className="flex flex-1 w-full pt-12 pb-4"> |
||||||
|
<Table |
||||||
|
data={CodeList || []} |
||||||
|
// data={[]}
|
||||||
|
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, |
||||||
|
CodeList: state.offCode.list, |
||||||
|
schema: state.offCode.schema, |
||||||
|
}); |
||||||
|
|
||||||
|
const mapDispatchToProps = { |
||||||
|
// getData: actions[source].list,
|
||||||
|
getData: actions[source].schoolList, |
||||||
|
setTabs: actions.table.setTab, |
||||||
|
update: actions[source].update, |
||||||
|
add: actions[source].add, |
||||||
|
}; |
||||||
|
|
||||||
|
export default connect( |
||||||
|
mapStateToProps, |
||||||
|
mapDispatchToProps |
||||||
|
)(DisCountCodeManagements); |
@ -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://api.andishmand.ir/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); |
@ -0,0 +1,93 @@ |
|||||||
|
|
||||||
|
|
||||||
|
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 ProductMangement = ({ |
||||||
|
info, |
||||||
|
getData, |
||||||
|
tabs, |
||||||
|
setTabs, |
||||||
|
add, |
||||||
|
update, |
||||||
|
productList, |
||||||
|
schema, |
||||||
|
}) => { |
||||||
|
useMemo(() => { |
||||||
|
getData({ num: 1000 }); |
||||||
|
}, []); |
||||||
|
console.log("productManagement render---------------------------------"); |
||||||
|
console.log(info); |
||||||
|
console.log(productList); |
||||||
|
console.log(schema); |
||||||
|
// 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); |
||||||
|
|
||||||
|
return ( |
||||||
|
<div |
||||||
|
className="UserManagement h-screen max-h-screen bg-[#F8F8F8] overflow-y-auto rtl relative" |
||||||
|
style={{ width: "calc(100vw - 120px)" }} |
||||||
|
> |
||||||
|
<div className="flex flex-1 w-full pt-12 pb-4"> |
||||||
|
<Table |
||||||
|
data={productList || []} |
||||||
|
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, |
||||||
|
productList: state.book.list, |
||||||
|
schema: state.book.schema, |
||||||
|
}); |
||||||
|
|
||||||
|
const mapDispatchToProps = { |
||||||
|
// getData: actions[source].list,
|
||||||
|
getData: actions[source].list, |
||||||
|
setTabs: actions.table.setTab, |
||||||
|
update: actions[source].update, |
||||||
|
add: actions[source].add, |
||||||
|
}; |
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(ProductMangement); |
@ -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