reza added edit and delete

temp
Reza_ashrafi 3 years ago
parent c6a7b91097
commit 3726ef9f14
  1. 17
      src/components/Dialog/index.js
  2. 7
      src/components/Empty/index.js
  3. 1
      src/redux/actions/index.js
  4. 8
      src/redux/actions/menu.js
  5. 6
      src/redux/actions/userAddress.js
  6. 2
      src/redux/actions/userFavorite.js
  7. 1
      src/redux/reducers/index.js
  8. 15
      src/redux/reducers/menu.js
  9. 12
      src/redux/reducers/userFavorite.js
  10. 55
      src/router.js
  11. 106
      src/views/Address/index.js
  12. 246
      src/views/Dashboard/layouts/Mobile/ProfileAddress/index.js

@ -4,14 +4,25 @@ import { dialog } from "../../redux/actions";
export const Dialog = ({ dialog, setDialog }) => {
const { text, type, accept } = dialog;
const exit = (e) => {
setDialog({ ...dialog, open: !dialog.open });
e.stopPropagation();
}
const acceptFunc = () => {
setDialog({ ...dialog, open: !dialog.open });
accept();
}
return (
<div
className="z-50 w-screen h-full fixed top-0 right-0 backdrop-filter blur-sm flex justify-center items-center"
onClick={() => setDialog({ ...dialog, open: !dialog.open })}
className="w-screen h-full fixed top-0 right-0 bg-gray-500 bg-opacity-10 backdrop-filter backdrop-blur-lg flex justify-center items-center"
style={{zIndex : 70}}
onClick={(e) => exit(e)}
>
<div
className={`flex flex-col items-center bg-white dark:bg-black dark:bg-opacity-30 backdrop-filter backdrop-blur-xl rounded-md p-5 shadow-2xl`}
style={{ minWidth: 300 }}
onClick={(e) => e.stopPropagation()}
>
{/* {type === "confirm" && (
<div className="w-full flex justify-end text-sm text-bla">exit</div>
@ -25,7 +36,7 @@ export const Dialog = ({ dialog, setDialog }) => {
<div className="flex flex-row gap-4 w-full">
<button
className="py-2.5 w-1/2 shadow-md rounded-sm bg-blueC0 text-white"
onClick={() => accept()}
onClick={() => acceptFunc()}
>
باشه
</button>

@ -3,8 +3,11 @@ import { connect } from "react-redux";
export const Empty = ({ text, buttonText, buttonAction }) => {
return (
<div className="flex-1 flex flex-col justify-center items-center">
<strong className="text-tiny font-medium text-gray1">{text}</strong>
<div
className="flex-1 flex flex-col justify-center items-center"
style={{ minHeight: 'calc(100vh - 120px)' }}
>
<strong className="text-lg font-bold text-gray1">{text}</strong>
</div>
);
};

@ -17,3 +17,4 @@ export {default as qr} from "./qr";
export {default as comment} from "./comment";
export {default as form} from "./form";
export {default as dialog} from "./dialog";
export {default as menu} from "./menu";

@ -0,0 +1,8 @@
const menu = {
set:
(data = {}) =>
async (dispatch) =>
await dispatch({ type: "menu/set", data }),
};
export default menu;

@ -8,12 +8,12 @@ const userAddress = {
info:
(data = {}) =>
async (dispatch) => {
await dispatch({ type: "userAddress/info", data });
await proxy.get("userAddress/info", data, { dispatch });
},
update:
(data = {}, data2 = {}) =>
async (dispatch) => {
await proxy.put("userAddress/update", data);
await proxy.put("userAddress/update", data, {dispatch});
await proxy.get("userAddress/list", data2, { dispatch });
},
add:
@ -25,7 +25,7 @@ const userAddress = {
del:
(data = {}, data2 = {}) =>
async (dispatch) => {
await proxy.delete("userAddress/delete", data);
await proxy.delete("userAddress/delete", data, { dispatch });
await proxy.get("userAddress/list", data2, { dispatch });
},
};

@ -4,7 +4,7 @@ const userFavorite = {
list:
(data = {}) =>
async (dispatch) => {
await proxy.get("userFavorite/list", data, { dispatch });
await proxy.post("userFavorite/list", data, { dispatch });
},
update:
(data = {}, data2 = {}) =>

@ -17,3 +17,4 @@ export {default as qr} from "./qr";
export {default as comment} from "./comment";
export {default as form} from "./form";
export {default as dialog} from "./dialog";
export {default as menu} from "./menu";

@ -0,0 +1,15 @@
const initialState = {
open : false,
};
export default function menu(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "menu/set":
return {
open : !state.open
};
default:
return state;
}
}

@ -8,23 +8,23 @@ const initialState = {
export default function userAddress(state = initialState, action) {
let { type, data } = action;
switch (type) {
case "userAddress/list":
case "userFavorite/list":
return {
...state,
loading: false,
list: data,
error: null,
};
case "userAddress/update":
case "userFavorite/update":
return { ...state, loading: false, error: null };
case "userAddress/add":
case "userFavorite/add":
toast.success('به لیست علاقهمندیها اضافه شد.');
return { ...state, loading: false, error: null };
case "userAddress/delete":
case "userFavorite/delete":
return { ...state, loading: false, error: null };
case "userAddress/loading":
case "userFavorite/loading":
return { ...state, loading: true };
case "userAddress/error":
case "userFavorite/error":
toast.error(data.message);
return { ...state, loading: false, error: data.message };
default:

@ -2,7 +2,7 @@ import React, { useEffect } from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { Navigate } from "react-router-dom";
import { connect } from "react-redux";
import { publicApi } from "./redux/actions";
import { publicApi, menu } from "./redux/actions";
import Navbar from "./components/Navbar";
import BG from "./components/BG";
import BottomNavigation from "./components/BottomNavigation";
@ -35,11 +35,16 @@ import Address from "./views/Address";
import Favorites from "./views/Favorites";
import Addresses from "./views/Dashboard/layouts/Mobile/ProfileAddress";
function Router({ isDark, isMobile, headerOptions, dialog }) {
function Router({ isDark, isMobile, headerOptions, dialog, menu, setMenu }) {
useEffect(() => {
window.addEventListener("scroll", () => {});
}, []);
const prevDefault = (e) => {
setMenu();
e.stopPropagation();
};
return (
<div className={`${isDark ? "dark" : ""}`}>
<div
@ -52,6 +57,13 @@ function Router({ isDark, isMobile, headerOptions, dialog }) {
" "
)}
>
{menu && (
<div
className="h-full w-screen fixed top-0 left-0 bg-opacity-0"
onClick={(e) => prevDefault(e)}
style={{ zIndex: 60 }}
></div>
)}
{dialog.open && <Dialog />}
<BrowserRouter>
{headerOptions?.shown && <Navbar headerOptions={headerOptions} />}
@ -375,6 +387,41 @@ function Router({ isDark, isMobile, headerOptions, dialog }) {
/>
}
/>
<Route
path="/editAddress/:id"
exact
element={
<Address
editPage={true}
headerOptions={{
logo: false,
hamburgerMenu: false,
qr: false,
title: "ویرایش آدرس",
shown: true,
menu: false,
back: true,
}}
/>
}
/>
<Route
path="/createAddress"
exact
element={
<Address
headerOptions={{
logo: false,
hamburgerMenu: false,
qr: false,
title: "آدرس جدید",
shown: true,
menu: false,
back: true,
}}
/>
}
/>
<Route
path="/favorites"
exact
@ -392,7 +439,7 @@ function Router({ isDark, isMobile, headerOptions, dialog }) {
/>
}
/>
<Route
<Route
path="/addresses"
exact
element={
@ -491,10 +538,12 @@ const mapStateToProps = (state) => ({
isLogin: state.user.status,
headerOptions: state.publicApi.headerOptions,
dialog: state.dialog.dialog,
menu: state.menu.open,
});
const mapDispatchToProps = {
setDesktopContentTransform: publicApi.setDesktopContentTransform,
setMenu: menu.set,
};
export default connect(mapStateToProps, mapDispatchToProps)(Router);

@ -1,7 +1,9 @@
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { useNavigate } from "react-router-dom";
import { publicApi, userAddress, dialog, user } from "../../redux/actions";
import onInput from "../../utils/onInput";
import location from "../../utils/location";
import Input from "../../components/Input";
import Select from "../../components/Select";
import Button from "../../components/Button";
@ -28,25 +30,58 @@ export const Address = ({
isDark,
setDialog,
profilePage,
editPage,
setProfileFields,
profileFields,
setProfile,
user,
setHeaderOptions,
headerOptions,
getAddress,
addressInfo,
updateAddress,
}) => {
const [addressFields, setAddressFields] = useState({});
const [mapAddress, setMapAddress] = useState(null);
const navigation = useNavigate();
useEffect(() => {
if (province.length <= 1) {
getProvince();
}
if(isMobile){
if (isMobile) {
setHeaderOptions(headerOptions);
}
if (editPage) {
getAddress({ id: location.getId() });
}
}, []);
useEffect(() => {
if (editPage && addressInfo) {
const {
firstName,
lastName,
cellphone,
phone,
provinceId,
address,
cityId,
postalCode,
} = addressInfo;
setAddressFields({
firstName,
lastName,
cellphone,
phone,
provinceId,
cityId,
postalCode,
});
setMapAddress(address);
}
}, [addressInfo]);
useEffect(() => {
if (addressFields?.provinceId) {
getCity({
@ -174,22 +209,52 @@ export const Address = ({
});
return;
}
if (editPage) {
updateAddress({
id : addressInfo.id,
firstName,
lastName,
cellphone,
phone,
address: mapAddress,
provinceId:
typeof provinceId === "number"
? provinceId
: provinces.filter((province) => province.name === provinceId)[0]
?.id,
cityId:
typeof cityId === "number"
? cityId
: cities.filter((city) => city.name === cityId)[0]?.id,
postalCode,
location: null,
});
} else {
createAddress({
firstName,
lastName,
cellphone,
phone,
address: mapAddress,
provinceId:
typeof provinceId === "number"
? provinceId
: provinces.filter((province) => province.name === provinceId)[0]
?.id,
cityId:
typeof cityId === "number"
? cityId
: cities.filter((city) => city.name === cityId)[0]?.id,
postalCode,
location: null,
});
}
createAddress({
firstName,
lastName,
cellphone,
phone,
address: mapAddress,
provinceId: provinces.filter(
(province) => province.name === provinceId
)[0]?.id,
cityId: cities.filter((city) => city.name === cityId)[0]?.id,
postalCode,
location: null,
});
setPhase("deliveryForm");
if (editPage) {
navigation(-1);
} else {
setPhase("deliveryForm");
}
};
const Header = ({ title, text }) => {
@ -470,11 +535,11 @@ export const Address = ({
}
backgroundColor="bg-blueC0"
border={{ color: "#196EC055", width: "0px" }}
width={profilePage ? '30%' : '100%'}
width={profilePage ? "30%" : "100%"}
color="text-white"
onClick={() => (profilePage ? submitProfile() : submit())}
/>
{!profilePage && (
{!isMobile && (
<button
className="bg-transparent mt-4 text-base py-3 flex flex-row justify-center items-center border-2 border-solid border-blueC0 text-green7B dark:text-blueC0 rounded-full"
onClick={() => setPhase("deliveryForm")}
@ -522,16 +587,19 @@ const mapStateToProps = (state) => ({
isMobile: state.publicApi.isMobile,
isDark: state.publicApi.isDark,
profileFields: state.user.profileFields,
addressInfo: state.userAddress.info,
});
const mapDispatchToProps = {
getProvince: publicApi.getProvince,
getCity: publicApi.getCity,
createAddress: userAddress.add,
updateAddress: userAddress.update,
getAddress: userAddress.info,
setDialog: dialog.set,
setProfileFields: user.setProfileFields,
setProfile: user.setProfile,
setHeaderOptions : publicApi.setHeaderOptions
setHeaderOptions: publicApi.setHeaderOptions,
};
export default connect(mapStateToProps, mapDispatchToProps)(Address);

@ -1,12 +1,19 @@
import React from "react";
import { connect } from "react-redux";
import { userAddress, userFactor, publicApi } from "../../../../../redux/actions";
import {
userAddress,
userFactor,
publicApi,
menu,
dialog,
} from "../../../../../redux/actions";
import { Link, useNavigate } from "react-router-dom";
//components
import Empty from "../../../../../components/Empty";
import Button from "../../../../../components/Button";
import FloatingButton from "../../../../../components/FloatingButton";
import { add } from "lodash";
const ProfileAddress = ({
addresses,
@ -20,83 +27,13 @@ const ProfileAddress = ({
mobile,
isDark,
headerOptions,
setHeaderOptions
setHeaderOptions,
setMenu,
menu,
deleteAddress,
setDialog,
}) => {
const navigation = useNavigate();
const Location = ({ address, active }) => {
return (
<div
className={`bg-opacity-5 border border-solid flex flex-row items-center w-full px-3 py-2 rounded-md mt-2 ${
active ? "bg-blueC0 border-blueC0" : "bg-gray-300 border-gray-300"
}`}
onClick={() =>
userAddressId === address?.id
? {}
: update({ userAddressId: address.id, userId })
}
>
<div className={"flex flex-col flex-1 mr-2"}>
{active && (
<div className={"w-full flex flex-row justify-between mb-3"}>
<div className={"flex flex-row items-center"}>
<strong className={"text-base font-bold text-gray1"}>
آدرس انتخابی شما
</strong>
<span className={"text-xs text-gray1 mr-2.5"}>فعال</span>
</div>
<svg xmlns="http://www.w3.org/2000/svg" width={24} height={24}>
<g fill="#07612c" data-name="vuesax/linear/more">
<path d="M10 19a2 2 0 1 0 2-2 2.006 2.006 0 0 0-2 2Z" />
<path
data-name="Vector"
d="M10 5a2 2 0 1 0 2-2 2.006 2.006 0 0 0-2 2ZM10 12a2 2 0 1 0 2-2 2.006 2.006 0 0 0-2 2Z"
/>
</g>
</svg>
</div>
)}
<div className={`flex w-full ${active ? "" : "flex-row"}`}>
<div className={"flex flex-col flex-1 mb-4"}>
<span className={"text-sm leading-6"}>
{"آدرس:" + " " + address.address}
</span>
<span className={"text-sm leading-6 mt-1.5"}>
{"نام:" + " " + address.firstName + " " + address.lastName}
</span>
<span className={"text-sm leading-6 mt-1.5"}>
{"کد پستی:" + " " + address.postalCode}
</span>
<span className={"text-sm leading-6 mt-1.5"}>
{"شماره تماس:" + " " + address.cellphone}
</span>
</div>
{!active && (
<svg xmlns="http://www.w3.org/2000/svg" width={24} height={24}>
<g fill={"#aaa"} data-name="vuesax/linear/more">
<path d="M10 19a2 2 0 1 0 2-2 2.006 2.006 0 0 0-2 2Z" />
<path
data-name="Vector"
d="M10 5a2 2 0 1 0 2-2 2.006 2.006 0 0 0-2 2ZM10 12a2 2 0 1 0 2-2 2.006 2.006 0 0 0-2 2Z"
/>
</g>
</svg>
)}
</div>
<Button
title="نمایش روی نقشه"
backgroundColor={isDark ? "bg-transparent" : "bg-blueC0"}
border={{
color: isDark ? "#ffffff55" : "#196EC055",
width: "0px",
}}
width="100%"
color={isDark ? "text-blueC0" : "text-white"}
onClick={() => {}}
/>
</div>
</div>
);
};
React.useEffect(() => {
setHeaderOptions(headerOptions);
@ -108,12 +45,19 @@ const ProfileAddress = ({
<div className="flex-1 flex flex-col relative">
{addresses.length > 0 ? (
<div className="w-full mt-2 px-4">
<div className="p-0 m-0 flex ">
<div className="p-0 m-0 flex flex-col">
{addresses.map((address, index) => (
<Location
address={address}
key={index}
active={userAddressId === address?.id}
isDark={isDark}
userId={userId}
update={update}
setMenu={setMenu}
menu={menu}
deleteAddress={deleteAddress}
setDialog={setDialog}
/>
))}
</div>
@ -130,6 +74,150 @@ const ProfileAddress = ({
);
};
const Location = ({
address,
active,
isDark,
userId,
update,
setMenu,
menu,
deleteAddress,
setDialog,
}) => {
const [locationMenu, setLocationMenu] = React.useState(false);
React.useEffect(() => {
if (locationMenu) {
setMenu();
}
}, [locationMenu]);
React.useEffect(() => {
if (!menu) {
setLocationMenu(false);
}
}, [menu]);
const delAddress = (id) => {
setMenu();
setDialog({
text: "آدرس رو حذف کنیم؟",
type: "confirm",
accept: () => deleteAddress({ id }),
open: true,
});
};
const clickOnMenu = (e) => {
setLocationMenu(true);
e.stopPropagation();
};
return (
<div
className={`bg-opacity-5 border border-solid flex flex-row items-center w-full px-3 py-2 rounded-md mt-2 relative ${
active ? "bg-blueC0 border-blueC0" : "bg-gray-300 border-gray-300"
}`}
onClick={() =>
active ? {} : update({ userAddressId: address.id, userId })
}
>
<div
className={`absolute left-8 top-0 transform transition-all origin-bottom-left ${
locationMenu ? "scale-100" : "scale-0"
} -translate-y-1/2 bg-white roundd-md flex flex-col gap-1 p-1 shadow-all divide-y divide-solid divide-gray-200`}
style={{ zIndex: 70 }}
onClick={(e) => e.stopPropagation()}
>
<Link
to={"/editAddress/" + address.id}
className="py-3 pr-2 pl-10 text-sm font-bold"
onClick={() => setMenu()}
>
ویرایش
</Link>
<button
className="py-3 pr-2 pl-10 border-none m-0 text-sm text-red19 font-bold"
onClick={() => delAddress(address.id)}
>
حذف
</button>
</div>
<div className={"flex flex-col flex-1 mr-2"}>
{active && (
<div className={"w-full flex flex-row justify-between mb-3"}>
<div className={"flex flex-row items-center"}>
<strong className={"text-base font-bold text-gray1"}>
آدرس انتخابی شما
</strong>
<span className={"text-xs text-gray1 mr-2.5"}>فعال</span>
</div>
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
onClick={(e) => clickOnMenu(e)}
>
<g fill="#07612c" data-name="vuesax/linear/more">
<path d="M10 19a2 2 0 1 0 2-2 2.006 2.006 0 0 0-2 2Z" />
<path
data-name="Vector"
d="M10 5a2 2 0 1 0 2-2 2.006 2.006 0 0 0-2 2ZM10 12a2 2 0 1 0 2-2 2.006 2.006 0 0 0-2 2Z"
/>
</g>
</svg>
</div>
)}
<div className={`flex w-full ${active ? "" : "flex-row"}`}>
<div className={"flex flex-col flex-1 mb-4"}>
<span className={"text-sm leading-6"}>
{"آدرس:" + " " + address.address}
</span>
<span className={"text-sm leading-6 mt-1.5"}>
{"نام:" + " " + address.firstName + " " + address.lastName}
</span>
<span className={"text-sm leading-6 mt-1.5"}>
{"کد پستی:" + " " + address.postalCode}
</span>
<span className={"text-sm leading-6 mt-1.5"}>
{"شماره تماس:" + " " + address.cellphone}
</span>
</div>
{!active && (
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
onClick={(e) => clickOnMenu(e)}
>
<g fill={"#aaa"} data-name="vuesax/linear/more">
<path d="M10 19a2 2 0 1 0 2-2 2.006 2.006 0 0 0-2 2Z" />
<path
data-name="Vector"
d="M10 5a2 2 0 1 0 2-2 2.006 2.006 0 0 0-2 2ZM10 12a2 2 0 1 0 2-2 2.006 2.006 0 0 0-2 2Z"
/>
</g>
</svg>
)}
</div>
<Button
title="نمایش روی نقشه"
backgroundColor={isDark ? "bg-transparent" : "bg-blueC0"}
border={{
color: isDark ? "#ffffff55" : "#196EC055",
width: "0px",
}}
width="100%"
color={isDark ? "text-blueC0" : "text-white"}
onClick={() => {}}
/>
</div>
</div>
);
};
const mapStateToProps = (state) => ({
userId: state.user.status?.id,
userAddressId: state.userFactor.info?.userAddressId,
@ -137,6 +225,7 @@ const mapStateToProps = (state) => ({
addresses: state.userAddress.list,
mobile: state.publicApi.mobile,
isDark: state.publicApi.isDark,
menu: state.menu.open,
});
const mapDispatchToProps = {
@ -144,6 +233,9 @@ const mapDispatchToProps = {
update: userFactor.update,
getList: userAddress.list,
setHeaderOptions: publicApi.setHeaderOptions,
setMenu: menu.set,
deleteAddress: userAddress.del,
setDialog: dialog.set,
};
export default connect(mapStateToProps, mapDispatchToProps)(ProfileAddress);

Loading…
Cancel
Save