parent
3e8736f0d8
commit
a9d2b22a6c
18 changed files with 476 additions and 68 deletions
@ -0,0 +1,32 @@ |
||||
import proxy from "../proxy"; |
||||
const comment = { |
||||
list: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await proxy.get("comment/list", data, { dispatch }), |
||||
info: |
||||
(data = {}) => |
||||
async (dispatch) => { |
||||
await proxy.get("comment/info", data, { dispatch }); |
||||
}, |
||||
add: |
||||
(data = {}, data2) => |
||||
async (dispatch) => { |
||||
await proxy.post("comment/add", data, { dispatch }); |
||||
if (data2) await proxy.get("book/info", data2, { dispatch }); |
||||
}, |
||||
del: |
||||
(data = {}, data2 = {}) => |
||||
async (dispatch) => { |
||||
await proxy.delete("ar/delete", data); |
||||
await proxy.get("ar/list", data2, { dispatch }); |
||||
}, |
||||
update: |
||||
(data = {}, data2 = {}) => |
||||
async (dispatch) => { |
||||
await proxy.put("ar/update", data); |
||||
await proxy.get("ar/list", data2, { dispatch }); |
||||
}, |
||||
}; |
||||
|
||||
export default comment; |
@ -0,0 +1,8 @@ |
||||
const dialog = { |
||||
set: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await dispatch({ type: "dialog/set", data }), |
||||
}; |
||||
|
||||
export default dialog; |
@ -0,0 +1,8 @@ |
||||
const form = { |
||||
setTicket: |
||||
(data = {}) => |
||||
async (dispatch) => |
||||
await dispatch({ type: "form/ticket", data }), |
||||
}; |
||||
|
||||
export default form; |
@ -0,0 +1,36 @@ |
||||
import {toast} from 'react-toastify'; |
||||
|
||||
const initialState = { |
||||
loading: false, |
||||
error: null, |
||||
list: null, |
||||
}; |
||||
|
||||
export default function comment(state = initialState, action) { |
||||
let { type, data } = action; |
||||
switch (type) { |
||||
case "comment/list": |
||||
return { ...state, loading: false, error: null }; |
||||
case "comment/update": |
||||
return { ...state, loading: false, error: null }; |
||||
case "comment/add": |
||||
toast.success("ثبت درخواست با موفقیت انجام شد"); |
||||
return { ...state, loading: false, error: null }; |
||||
case "comment/delete": |
||||
return { ...state, loading: false, error: null }; |
||||
case "comment/info": |
||||
return { |
||||
...state, |
||||
loading: false, |
||||
list: data, |
||||
error: null, |
||||
}; |
||||
case "comment/loading": |
||||
return { ...state, loading: true }; |
||||
case "comment/error": |
||||
toast.error(data.message); |
||||
return { ...state, loading: false, error: data.message }; |
||||
default: |
||||
return state; |
||||
} |
||||
} |
@ -0,0 +1,21 @@ |
||||
const initialState = { |
||||
dialog: { |
||||
text: null, |
||||
type: null, |
||||
accept: null, |
||||
open: null, |
||||
}, |
||||
}; |
||||
|
||||
export default function dialog(state = initialState, action) { |
||||
let { type, data } = action; |
||||
switch (type) { |
||||
case "dialog/set": |
||||
return { |
||||
...state, |
||||
dialog : {...data}, |
||||
}; |
||||
default: |
||||
return state; |
||||
} |
||||
} |
@ -0,0 +1,26 @@ |
||||
import { toast } from "react-toastify"; |
||||
|
||||
const initialState = { |
||||
loading: false, |
||||
error: null, |
||||
ticket: {}, |
||||
}; |
||||
export default function form(state = initialState, action) { |
||||
let { type, data } = action; |
||||
switch (type) { |
||||
case "form/ticket": |
||||
return { |
||||
...state, |
||||
loading: false, |
||||
ticket: { ...state.ticket, [data.name]: data.value }, |
||||
error: null, |
||||
}; |
||||
case "form/loading": |
||||
return { ...state, loading: true }; |
||||
case "form/error": |
||||
toast.error(data.message); |
||||
return { ...state, loading: false, error: data.message }; |
||||
default: |
||||
return state; |
||||
} |
||||
} |
@ -0,0 +1,180 @@ |
||||
import React, { useMemo, useEffect, useCallback } from "react"; |
||||
import { connect } from "react-redux"; |
||||
import { |
||||
userProduct, |
||||
comment, |
||||
file, |
||||
form, |
||||
dialog, |
||||
} from "../../../redux/actions"; |
||||
import onInput from "../../../utils/onInput"; |
||||
|
||||
//components
|
||||
import Input from "../../../components/Input"; |
||||
import Textarea from "../../../components/Textarea"; |
||||
import Button from "../../../components/Button"; |
||||
import Select from "../../../components/Select"; |
||||
import Upload from "./Upload"; |
||||
|
||||
export const Ticket = ({ |
||||
isDark, |
||||
myProductList, |
||||
status, |
||||
ticket, |
||||
getUserProductList, |
||||
submit, |
||||
upload, |
||||
setTicket, |
||||
grades, |
||||
setDialog, |
||||
}) => { |
||||
let opt = useMemo( |
||||
() => ["واحد مورد نظر", "واحد فروش", "واحد فنی", "واحد محتوایی"], |
||||
[status] |
||||
); |
||||
|
||||
useEffect(() => { |
||||
if (myProductList.length === 0 && status) { |
||||
getUserProductList(); |
||||
} |
||||
}, []); |
||||
|
||||
const addFile = useCallback( |
||||
(name, value) => { |
||||
upload({ file: value, target: name }); |
||||
setTicket({ name, value }); |
||||
}, |
||||
[status] |
||||
); |
||||
|
||||
const send = useCallback(async () => { |
||||
if (!ticket?.subject) { |
||||
setDialog({ |
||||
text: "موضوع پیام خود را وارد کنید.", |
||||
type: "alert", |
||||
accept: () => {}, |
||||
open: true, |
||||
}); |
||||
}else if(!ticket?.unit){ |
||||
setDialog({ |
||||
text: "واحد مورد نظر خود را وارد نکرده اید.", |
||||
type: "alert", |
||||
accept: () => {}, |
||||
open: true, |
||||
}); |
||||
} else { |
||||
const data = { |
||||
fileId: null, |
||||
text: ticket?.text, |
||||
name: !status ? ticket?.name : status.firstName + " " + status.lastName, |
||||
cellphone: !status ? ticket?.cellphone : status?.cellphone, |
||||
unit: ticket?.unit, |
||||
bookId: ticket?.bookId, |
||||
subject: ticket?.subject, |
||||
userId: status?.userId, |
||||
}; |
||||
await submit(data); |
||||
} |
||||
}, [status]); |
||||
|
||||
return ( |
||||
<div className="flex flex-col flex-1"> |
||||
{!status && ( |
||||
<> |
||||
<Input |
||||
width="55%" |
||||
label="نام و نام خانوادگی" |
||||
name="name" |
||||
onChange={(name, value) => setTicket({ name, value })} |
||||
value={ticket?.name || ""} |
||||
regex={(val) => val} |
||||
/> |
||||
<Input |
||||
width="55%" |
||||
label="شماره تماس" |
||||
name="cellphone" |
||||
onChange={(name, value) => setTicket({ name, value })} |
||||
value={ticket?.cellphone || ""} |
||||
regex={(val) => onInput.phonenumber(val)} |
||||
maxLength="11" |
||||
/> |
||||
</> |
||||
)} |
||||
<Select |
||||
options={status && myProductList?.length ? opt : opt.slice(0, 3)} |
||||
name="unit" |
||||
onChange={(name, value) => setTicket({ name, value })} |
||||
width={"w-10/12"} |
||||
backgroundColor={isDark ? "dark:bg-transparent dark:text-white" : ""} |
||||
fill={isDark ? "fill-white" : "fill-gray-600"} |
||||
/> |
||||
{ticket?.unit === "واحد محتوایی" && ( |
||||
<Select |
||||
name="bookId" |
||||
options={[ |
||||
...new Set( |
||||
myProductList?.map((item) => [ |
||||
item?.product?.book?.id, |
||||
`${item?.product?.book.name} پایه ${ |
||||
Object.values(grades)[item.product.book.gradeId] |
||||
}`,
|
||||
]) || [] |
||||
), |
||||
]} |
||||
onChange={(name, value) => setTicket({ name, value })} |
||||
width={"w-10/12"} |
||||
backgroundColor={isDark ? "dark:bg-transparent dark:text-white" : ""} |
||||
fill={isDark ? "fill-white" : "fill-gray-600"} |
||||
/> |
||||
)} |
||||
<Input |
||||
width="85%" |
||||
name="subject" |
||||
onChange={(name, value) => setTicket({ name, value })} |
||||
value={ticket?.subject || ""} |
||||
regex={(val) => val} |
||||
label="موضوع" |
||||
/> |
||||
<Textarea |
||||
placeholder="پیام خود را اینجا بنویسید" |
||||
name="text" |
||||
onChange={(name, value) => setTicket({ name, value })} |
||||
value={ticket?.text || ""} |
||||
/> |
||||
<br /> |
||||
<Upload |
||||
onChange={(name, value) => addFile(name, value)} |
||||
name="file" |
||||
value={ticket?.file} |
||||
/> |
||||
<br /> |
||||
<Button |
||||
title="ارسال پیام" |
||||
backgroundColor={isDark ? "bg-blueC0" : "bg-blueC0"} |
||||
border={{ color: isDark ? "#ffffff55" : "#196EC055", width: "0px" }} |
||||
width="100%" |
||||
color={"text-white"} |
||||
selectable={true} |
||||
onClick={() => send()} |
||||
/> |
||||
</div> |
||||
); |
||||
}; |
||||
|
||||
const mapStateToProps = (state) => ({ |
||||
isDark: state.publicApi.isDark, |
||||
myProductList: state.userProduct.myList, |
||||
status: state.user.status, |
||||
ticket: state.form.ticket, |
||||
grades: state.publicApi.grades, |
||||
}); |
||||
|
||||
const mapDispatchToProps = { |
||||
getUserProductList: userProduct.myList, |
||||
submit: comment.add, |
||||
upload: file.upload, |
||||
setTicket: form.setTicket, |
||||
setDialog: dialog.set, |
||||
}; |
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Ticket); |
@ -0,0 +1,68 @@ |
||||
import React from "react"; |
||||
import { connect } from "react-redux"; |
||||
|
||||
import "./index.scss"; |
||||
|
||||
function Document({ onChange, name, value, isMobile }) { |
||||
return ( |
||||
<> |
||||
{isMobile ? ( |
||||
<div className="support__document flex justify-center items-center mb-3"> |
||||
<input |
||||
type="file" |
||||
name={name} |
||||
onChange={(e) => onChange(e.target.name, e.target.files[0])} |
||||
/> |
||||
{value ? ( |
||||
<span |
||||
style={{ |
||||
width: "100%", |
||||
textAlign: "center", |
||||
margin: "auto", |
||||
}} |
||||
> |
||||
{value?.name || "تصویر بارگزاری شد"} |
||||
</span> |
||||
) : ( |
||||
<span>در صورت نیاز تصویر مرتبط را انتخاب کنید.</span> |
||||
)} |
||||
</div> |
||||
) : ( |
||||
<div className="support__document flex justify-center items-center"> |
||||
<input |
||||
type="file" |
||||
name={name} |
||||
onChange={(e) => onChange(e.target.name, e.target.files[0])} |
||||
/>{" "} |
||||
{value ? ( |
||||
<span |
||||
style={{ |
||||
width: "100%", |
||||
textAlign: "center", |
||||
margin: "auto", |
||||
}} |
||||
> |
||||
{value?.name || "فایل ثبت شد"} |
||||
</span> |
||||
) : ( |
||||
<span |
||||
style={{ |
||||
width: "100%", |
||||
textAlign: "center", |
||||
margin: "auto", |
||||
}} |
||||
> |
||||
در صورت نیاز تصویر مرتبط را انتخاب کنید. |
||||
</span> |
||||
)} |
||||
</div> |
||||
)} |
||||
</> |
||||
); |
||||
} |
||||
|
||||
const mapStateToProps = (state) => ({ |
||||
isMobile: state.publicApi.isMobile, |
||||
}); |
||||
|
||||
export default connect(mapStateToProps)(Document); |
@ -0,0 +1,28 @@ |
||||
.support { |
||||
&__document { |
||||
color: gray !important; |
||||
margin: 10px auto; |
||||
width: 100%; |
||||
height: 50px; |
||||
border-radius: 10px; |
||||
border: 2px dashed #d1d1d1; |
||||
position: relative; |
||||
input { |
||||
width: 100%; |
||||
height: 100%; |
||||
position: absolute; |
||||
left: 0px; |
||||
top: 0px; |
||||
opacity: 0; |
||||
} |
||||
img { |
||||
width: 100%; |
||||
height: 100%; |
||||
object-fit: cover; |
||||
border-radius: 50%; |
||||
} |
||||
span { |
||||
color: #afafaf; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue