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. 53
      src/router.js
  11. 86
      src/views/Address/index.js
  12. 174
      src/views/Dashboard/layouts/Mobile/ProfileAddress/index.js

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

@ -3,8 +3,11 @@ import { connect } from "react-redux";
export const Empty = ({ text, buttonText, buttonAction }) => { export const Empty = ({ text, buttonText, buttonAction }) => {
return ( return (
<div className="flex-1 flex flex-col justify-center items-center"> <div
<strong className="text-tiny font-medium text-gray1">{text}</strong> 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> </div>
); );
}; };

@ -17,3 +17,4 @@ export {default as qr} from "./qr";
export {default as comment} from "./comment"; export {default as comment} from "./comment";
export {default as form} from "./form"; export {default as form} from "./form";
export {default as dialog} from "./dialog"; 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: info:
(data = {}) => (data = {}) =>
async (dispatch) => { async (dispatch) => {
await dispatch({ type: "userAddress/info", data }); await proxy.get("userAddress/info", data, { dispatch });
}, },
update: update:
(data = {}, data2 = {}) => (data = {}, data2 = {}) =>
async (dispatch) => { async (dispatch) => {
await proxy.put("userAddress/update", data); await proxy.put("userAddress/update", data, {dispatch});
await proxy.get("userAddress/list", data2, { dispatch }); await proxy.get("userAddress/list", data2, { dispatch });
}, },
add: add:
@ -25,7 +25,7 @@ const userAddress = {
del: del:
(data = {}, data2 = {}) => (data = {}, data2 = {}) =>
async (dispatch) => { async (dispatch) => {
await proxy.delete("userAddress/delete", data); await proxy.delete("userAddress/delete", data, { dispatch });
await proxy.get("userAddress/list", data2, { dispatch }); await proxy.get("userAddress/list", data2, { dispatch });
}, },
}; };

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

@ -17,3 +17,4 @@ export {default as qr} from "./qr";
export {default as comment} from "./comment"; export {default as comment} from "./comment";
export {default as form} from "./form"; export {default as form} from "./form";
export {default as dialog} from "./dialog"; 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) { export default function userAddress(state = initialState, action) {
let { type, data } = action; let { type, data } = action;
switch (type) { switch (type) {
case "userAddress/list": case "userFavorite/list":
return { return {
...state, ...state,
loading: false, loading: false,
list: data, list: data,
error: null, error: null,
}; };
case "userAddress/update": case "userFavorite/update":
return { ...state, loading: false, error: null }; return { ...state, loading: false, error: null };
case "userAddress/add": case "userFavorite/add":
toast.success('به لیست علاقهمندیها اضافه شد.'); toast.success('به لیست علاقهمندیها اضافه شد.');
return { ...state, loading: false, error: null }; return { ...state, loading: false, error: null };
case "userAddress/delete": case "userFavorite/delete":
return { ...state, loading: false, error: null }; return { ...state, loading: false, error: null };
case "userAddress/loading": case "userFavorite/loading":
return { ...state, loading: true }; return { ...state, loading: true };
case "userAddress/error": case "userFavorite/error":
toast.error(data.message); toast.error(data.message);
return { ...state, loading: false, error: data.message }; return { ...state, loading: false, error: data.message };
default: default:

@ -2,7 +2,7 @@ import React, { useEffect } from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom"; import { BrowserRouter, Routes, Route } from "react-router-dom";
import { Navigate } from "react-router-dom"; import { Navigate } from "react-router-dom";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { publicApi } from "./redux/actions"; import { publicApi, menu } from "./redux/actions";
import Navbar from "./components/Navbar"; import Navbar from "./components/Navbar";
import BG from "./components/BG"; import BG from "./components/BG";
import BottomNavigation from "./components/BottomNavigation"; import BottomNavigation from "./components/BottomNavigation";
@ -35,11 +35,16 @@ import Address from "./views/Address";
import Favorites from "./views/Favorites"; import Favorites from "./views/Favorites";
import Addresses from "./views/Dashboard/layouts/Mobile/ProfileAddress"; import Addresses from "./views/Dashboard/layouts/Mobile/ProfileAddress";
function Router({ isDark, isMobile, headerOptions, dialog }) { function Router({ isDark, isMobile, headerOptions, dialog, menu, setMenu }) {
useEffect(() => { useEffect(() => {
window.addEventListener("scroll", () => {}); window.addEventListener("scroll", () => {});
}, []); }, []);
const prevDefault = (e) => {
setMenu();
e.stopPropagation();
};
return ( return (
<div className={`${isDark ? "dark" : ""}`}> <div className={`${isDark ? "dark" : ""}`}>
<div <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 />} {dialog.open && <Dialog />}
<BrowserRouter> <BrowserRouter>
{headerOptions?.shown && <Navbar headerOptions={headerOptions} />} {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 <Route
path="/favorites" path="/favorites"
exact exact
@ -491,10 +538,12 @@ const mapStateToProps = (state) => ({
isLogin: state.user.status, isLogin: state.user.status,
headerOptions: state.publicApi.headerOptions, headerOptions: state.publicApi.headerOptions,
dialog: state.dialog.dialog, dialog: state.dialog.dialog,
menu: state.menu.open,
}); });
const mapDispatchToProps = { const mapDispatchToProps = {
setDesktopContentTransform: publicApi.setDesktopContentTransform, setDesktopContentTransform: publicApi.setDesktopContentTransform,
setMenu: menu.set,
}; };
export default connect(mapStateToProps, mapDispatchToProps)(Router); export default connect(mapStateToProps, mapDispatchToProps)(Router);

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

@ -1,12 +1,19 @@
import React from "react"; import React from "react";
import { connect } from "react-redux"; 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"; import { Link, useNavigate } from "react-router-dom";
//components //components
import Empty from "../../../../../components/Empty"; import Empty from "../../../../../components/Empty";
import Button from "../../../../../components/Button"; import Button from "../../../../../components/Button";
import FloatingButton from "../../../../../components/FloatingButton"; import FloatingButton from "../../../../../components/FloatingButton";
import { add } from "lodash";
const ProfileAddress = ({ const ProfileAddress = ({
addresses, addresses,
@ -20,21 +27,124 @@ const ProfileAddress = ({
mobile, mobile,
isDark, isDark,
headerOptions, headerOptions,
setHeaderOptions setHeaderOptions,
setMenu,
menu,
deleteAddress,
setDialog,
}) => { }) => {
const navigation = useNavigate(); const navigation = useNavigate();
const Location = ({ address, active }) => {
React.useEffect(() => {
setHeaderOptions(headerOptions);
getFactorInfo({ userId });
getList();
}, []);
return (
<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 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>
</div>
) : (
<Empty text="هیچ آدرسی ثبت نشده :(" />
)}
<FloatingButton
action={() => navigation("/createAddress")}
position={{ bottom: 100, right: 16 }}
size={16}
/>
</div>
);
};
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 ( return (
<div <div
className={`bg-opacity-5 border border-solid flex flex-row items-center w-full px-3 py-2 rounded-md mt-2 ${ 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" active ? "bg-blueC0 border-blueC0" : "bg-gray-300 border-gray-300"
}`} }`}
onClick={() => onClick={() =>
userAddressId === address?.id active ? {} : update({ userAddressId: address.id, userId })
? {}
: 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"}> <div className={"flex flex-col flex-1 mr-2"}>
{active && ( {active && (
<div className={"w-full flex flex-row justify-between mb-3"}> <div className={"w-full flex flex-row justify-between mb-3"}>
@ -44,7 +154,12 @@ const ProfileAddress = ({
</strong> </strong>
<span className={"text-xs text-gray1 mr-2.5"}>فعال</span> <span className={"text-xs text-gray1 mr-2.5"}>فعال</span>
</div> </div>
<svg xmlns="http://www.w3.org/2000/svg" width={24} height={24}> <svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
onClick={(e) => clickOnMenu(e)}
>
<g fill="#07612c" data-name="vuesax/linear/more"> <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 d="M10 19a2 2 0 1 0 2-2 2.006 2.006 0 0 0-2 2Z" />
<path <path
@ -71,7 +186,12 @@ const ProfileAddress = ({
</span> </span>
</div> </div>
{!active && ( {!active && (
<svg xmlns="http://www.w3.org/2000/svg" width={24} height={24}> <svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
onClick={(e) => clickOnMenu(e)}
>
<g fill={"#aaa"} data-name="vuesax/linear/more"> <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 d="M10 19a2 2 0 1 0 2-2 2.006 2.006 0 0 0-2 2Z" />
<path <path
@ -96,38 +216,6 @@ const ProfileAddress = ({
</div> </div>
</div> </div>
); );
};
React.useEffect(() => {
setHeaderOptions(headerOptions);
getFactorInfo({ userId });
getList();
}, []);
return (
<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 ">
{addresses.map((address, index) => (
<Location
address={address}
key={index}
active={userAddressId === address?.id}
/>
))}
</div>
</div>
) : (
<Empty text="هیچ آدرسی ثبت نشده :(" />
)}
<FloatingButton
action={() => navigation("/createAddress")}
position={{ bottom: 100, right: 16 }}
size={16}
/>
</div>
);
}; };
const mapStateToProps = (state) => ({ const mapStateToProps = (state) => ({
@ -137,6 +225,7 @@ const mapStateToProps = (state) => ({
addresses: state.userAddress.list, addresses: state.userAddress.list,
mobile: state.publicApi.mobile, mobile: state.publicApi.mobile,
isDark: state.publicApi.isDark, isDark: state.publicApi.isDark,
menu: state.menu.open,
}); });
const mapDispatchToProps = { const mapDispatchToProps = {
@ -144,6 +233,9 @@ const mapDispatchToProps = {
update: userFactor.update, update: userFactor.update,
getList: userAddress.list, getList: userAddress.list,
setHeaderOptions: publicApi.setHeaderOptions, setHeaderOptions: publicApi.setHeaderOptions,
setMenu: menu.set,
deleteAddress: userAddress.del,
setDialog: dialog.set,
}; };
export default connect(mapStateToProps, mapDispatchToProps)(ProfileAddress); export default connect(mapStateToProps, mapDispatchToProps)(ProfileAddress);

Loading…
Cancel
Save