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