diff --git a/public/assets/css/all.css b/public/assets/css/all.css index faaddbf..4097a9b 100644 --- a/public/assets/css/all.css +++ b/public/assets/css/all.css @@ -10425,7 +10425,7 @@ ul.pagination li:hover a { } .disable-mobile { - display: none; + display: none !important; } .enable-mobile { diff --git a/src/App.js b/src/App.js index 7f7a8df..91aef56 100644 --- a/src/App.js +++ b/src/App.js @@ -11,6 +11,7 @@ import {LoginPage} from './_containers/LoginPage/index' import { ForgotPasswordPage } from "./_containers/ForgotPasswordPage"; import RegisterPage from "./_containers/RegisterPage"; import HomePage from "./_containers/HomePage"; +import ListCustomer from "./_containers/ListCustomer"; function App() { const dispatch = useDispatch(); @@ -51,6 +52,12 @@ function App() { component={HomePage} authentication={authentication} /> + diff --git a/src/_components/Auth/InputDate/index.js b/src/_components/Auth/InputDate/index.js index 1846b31..af4f344 100644 --- a/src/_components/Auth/InputDate/index.js +++ b/src/_components/Auth/InputDate/index.js @@ -23,7 +23,7 @@ const InputDate = (props) => { }; return ( -
+
{props.errorText ? (
{props.errorText} diff --git a/src/_components/Auth/InputText/index.js b/src/_components/Auth/InputText/index.js index 3273a59..5477fea 100644 --- a/src/_components/Auth/InputText/index.js +++ b/src/_components/Auth/InputText/index.js @@ -93,7 +93,7 @@ const InputText = (props) => { }; return ( -
+
{props.errorText && props?.typeErrText != "underAbsolute" ? (
{ await apiCaller('/logout', "POST", {}) window.location.href = "/login"; localStorage.removeItem("authentication"); localStorage.removeItem("access_token"); + setIsOpenMenuMobile(false) } + const renderListHeader = () => { + return ( + <> + + "header-item" + (isActive ? " header-item-selected" : "") + } + onClick={() => setIsOpenMenuMobile(false)} + > + Thông tin chung + + + "header-item" + (isActive ? " header-item-selected" : "") + } + onClick={() => setIsOpenMenuMobile(false)} + > + Danh sách khách hàng + + + ) + } + + const handleClickOutside = (event) => { + if (menuMobileRef.current && !menuMobileRef.current.contains(event.target)) { + setIsOpenMenuMobile(false); + } + }; + + useEffect(() => { + document.addEventListener('click', handleClickOutside, true); + return () => { + document.removeEventListener('click', handleClickOutside, true); + }; + }, []); + return (
@@ -22,9 +64,23 @@ export default function HeaderMain() { {"Logo"}
-
setIsHoverLogout(true)} onMouseOut={() => setIsHoverLogout(false)} onClick={handleLogout}> - - {isHoverLogout && Đăng xuất} +
+
+ {renderListHeader()} +
+
setIsHoverLogout(true)} onMouseOut={() => setIsHoverLogout(false)} onClick={handleLogout}> + + {isHoverLogout && Đăng xuất} +
+
+
+
+ setIsOpenMenuMobile(!isOpenMenuMobile)} xmlns="http://www.w3.org/2000/svg" width="36" height="36" viewBox="0 0 24 24"> + {isOpenMenuMobile &&
+ {renderListHeader()} +
Đăng xuất
+
} +
diff --git a/src/_containers/HomePage/HomePage.style.scss b/src/_containers/HomePage/HomePage.style.scss index dea3b66..841ddce 100644 --- a/src/_containers/HomePage/HomePage.style.scss +++ b/src/_containers/HomePage/HomePage.style.scss @@ -46,7 +46,7 @@ .name-agency { font-size: 28px; font-weight: 700; - padding-top: 10px; + padding-top: 6px; @include screen_mobile { padding-top: 0; @@ -70,6 +70,7 @@ .box-link { flex-direction: column; + .title-box-link { font-size: 24px; font-weight: 700; diff --git a/src/_containers/HomePage/index.js b/src/_containers/HomePage/index.js index 3244e1a..2e264d4 100644 --- a/src/_containers/HomePage/index.js +++ b/src/_containers/HomePage/index.js @@ -24,7 +24,8 @@ export default function HomePage() { const authentication = useSelector((state) => state.authentication); const handleCopy = (type, value) => { - navigator.clipboard.writeText(value) + const link = value?.trim()?.substring(0,5)?.includes('http') ? value : `https://${value?.trim()}` + navigator.clipboard.writeText(link) if (!!isCopied?.[type]) { return; } @@ -52,15 +53,29 @@ export default function HomePage() { ) } - const renderInfoAgencyItem = (text) => { + const renderIconInfoAgency = (type) => { + switch (type) { + case 'birthday': + return ( + + ); + case 'phone': + return ( + + ); + case 'email': + return ( + + ) + default: + return null; + } + } + + const renderInfoAgencyItem = (text, type) => { return (
- - - + {renderIconInfoAgency(type)} {text}
) @@ -103,14 +118,14 @@ export default function HomePage() { {authentication.fullname}

- {renderInfoAgencyItem(moment(authentication.birthday).format("DD/MM/YYYY"))} - {renderInfoAgencyItem(authentication.phone)} - {renderInfoAgencyItem(authentication.email)} + {renderInfoAgencyItem(moment(authentication.birthday).format("DD/MM/YYYY"), 'birthday')} + {renderInfoAgencyItem(authentication.phone, 'phone')} + {renderInfoAgencyItem(authentication.email, 'email')}
{renderBoxLink('Link Đăng ký tuyến dưới', authentication.downline_register, homeType.REGISTER)} - {/* {renderBoxLink('Link Landing page cho khách hàng', authentication.promotional_link, homeType.LANDING)} */} + {renderBoxLink('Link Landing page cho khách hàng', authentication.promotional_link, homeType.LANDING)}
diff --git a/src/_containers/ListCustomer/ListCustomer.style.scss b/src/_containers/ListCustomer/ListCustomer.style.scss new file mode 100644 index 0000000..8062d73 --- /dev/null +++ b/src/_containers/ListCustomer/ListCustomer.style.scss @@ -0,0 +1,161 @@ +@import "/src/_styles/mixin"; + +.main-container { + + @include screen_mobile { + padding: 0 16px; + } + + .filter-container { + display: flex; + flex-direction: column; + + .filter-form { + display: flex; + align-items: center; + gap: 24px; + + @include screen_mobile { + flex-direction: column; + gap: 0; + align-items: unset; + } + + .input-base-filter { + height: 48px; + + .icon_label { + margin-right: 12px; + } + } + + .keyword-filter-form { + flex: 1; + } + + .date-filter-form { + flex: 1; + display: flex; + gap: 24px; + + @include screen_mobile { + gap: 16px; + } + } + + .input-container { + flex: 1; + } + } + + .filter-action { + display: flex; + align-items: center; + justify-content: flex-end; + gap: 24px; + + @include screen_mobile { + justify-content: center; + } + + .btn-filter { + display: flex; + align-items: center; + height: 40px; + border-radius: 20px; + line-height: 40px; + padding: 0 25px; + font-size: 16px; + border: none; + font-family: 'Myriadpro-SemiBold'; + + svg { + margin-right: 8px; + } + } + + .btn-cancel-filter { + color: #4b4a4a; + background-color: #DDDDDD; + } + + .btn-cancel-filter:hover { + opacity: 0.6; + } + } + } + + .list-customer-container { + margin-top: 64px; + + .total-customer { + font-weight: 700; + margin-bottom: 16px; + } + + .empty-text { + font-weight: 700; + font-size: 18px; + text-align: center; + } + + .list-customer { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(48.6%, 1fr)); + gap: 24px; + + .customer-item { + // flex: 1 1 300px; + padding: 16px; + border-radius: 24px; + border: 1px solid #E1E1E1; + box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px; + + .customer-name { + font-size: 24px; + font-weight: 700; + margin-bottom: 16px; + } + + .customer-row { + display: flex; + gap: 16px; + margin-bottom: 8px; + } + + .customer-row.message .customer-info { + width: 100%; + } + + .customer-row-mobile { + @include screen_mobile { + flex-direction: column; + gap: 8px; + } + + .customer-info { + @include screen_mobile { + width: 100%; + } + } + } + + .customer-info { + width: 50%; + display: flex; + gap: 8px; + + svg { + width: 24px; + height: 24px; + } + + span { + flex: 1; + text-align: justify; + } + } + } + } + } +} \ No newline at end of file diff --git a/src/_containers/ListCustomer/index.js b/src/_containers/ListCustomer/index.js new file mode 100644 index 0000000..f0b8ef1 --- /dev/null +++ b/src/_containers/ListCustomer/index.js @@ -0,0 +1,178 @@ +import { useEffect, useState } from "react"; +import InputText from "../../_components/Auth/InputText"; +import HeaderMain from "../../_components/Header/HeaderMain"; +import InputDate from "../../_components/Auth/InputDate"; +import './ListCustomer.style.scss' +import { apiCaller } from "../../_helpers"; +import { configConstants } from "../../_constants"; +import dayjs from "dayjs"; + +export default function ListCustomer() { + const [filter, setFilter] = useState({ + keyword: '', + start_date: '', + end_date: '' + }) + const [listCustomer, setListCustomer] = useState([]) + const [isLoading, setIsLoading] = useState(false) + const [isFilter, setIsFilter] = useState(false) + + const getData = async (dataFilter) => { + setIsLoading(true) + const endPoint = '/agent/get_customer?' + + (!!dataFilter?.keyword ? `keyword=${dataFilter.keyword}&` : '') + + (!!dataFilter?.start_date ? `start_date=${dayjs(dataFilter.start_date).format('YYYY-MM-DD')}&` : '') + + (!!dataFilter?.end_date ? `end_date=${dayjs(dataFilter.end_date).format('YYYY-MM-DD')}` : ''); + try { + const res = await apiCaller(endPoint, 'GET', {}, null, false, configConstants.API_URL_SETEST, true, true) + setIsLoading(false) + if(res?.status) { + setListCustomer(res?.data) + } + } catch (err) { + setIsLoading(false) + } + } + + const changeFilter = (key, value) => { + setFilter(prev => ({ + ...prev, + [key]: value + })) + } + + const validateFilter = () => { + return !!filter.keyword || !!filter.start_date || !!filter.end_date + } + + const handleCancelFilter = () => { + const iniFilter = { + end_date: '', + keyword: '', + start_date: '' + } + setIsFilter(false) + setFilter(iniFilter) + getData(iniFilter) + } + + const handleFilter = () => { + setIsFilter(true) + getData(filter) + } + + useEffect(() => { + getData(filter) + }, []) + + const renderIconKeyWord = () => { + return ( + + ) + } + + const renderIconDate = () => { + return ( + + ) + } + + return ( +
+ +
+
+
+
+
+
+ changeFilter('keyword', text)} + type="text" + name="keyword" + placeholder="Nhập tên / số điện thoại / email" + autoFocus={true} + renderLabelIcon={renderIconKeyWord} + /> +
+
+ changeFilter('start_date', date)} + name="start_date" + renderLabelIcon={renderIconDate} + placeholder={"Từ ngày"} + maxDate={new Date()} + /> + changeFilter('end_date', date)} + name="end_date" + renderLabelIcon={renderIconDate} + placeholder={"Đến ngày"} + maxDate={new Date()} + /> +
+
+
+ + +
+
+ +
+ {!!listCustomer.length &&

{`Tổng số khách hàng: ${listCustomer.length}`}

} +
+ {listCustomer?.map(item => ( +
+

{item?.guest_name}

+
+
+ + {item?.phone} +
+
+ + {item?.email} +
+
+
+
+ + {dayjs(item?.date_receive).format('DD/MM/YYYY')} +
+ {!!item?.grade &&
+ + {`Lớp ${item?.grade}`} +
} +
+ {item?.message &&
+
+ + {item?.message} +
+
} +
+ ))} +
+ {!listCustomer.length && !isLoading &&

Không có dữ liệu.

} +
+
+
+
+
+ ) +} \ No newline at end of file diff --git a/src/_helpers/apiCaller.js b/src/_helpers/apiCaller.js index dee98a8..3370081 100644 --- a/src/_helpers/apiCaller.js +++ b/src/_helpers/apiCaller.js @@ -18,24 +18,25 @@ export function apiCaller( isLoading = true, isFullResponse = false, ) { - if (headers === undefined || headers === null) { + // if (headers === undefined || headers === null) { headers = { "X-API-KEY": configConstants.API_KEY, + Authorization: `Bearer ${JSON.parse(localStorage.getItem("access_token"))}`, }; - if (localStorage.getItem("authentication")) { - let authentication = JSON.parse(localStorage.getItem("authentication")); - headers["jwt_token"] = authentication.jwt_token; - } - } else { - if (localStorage.getItem("authentication")) { - let authentication = JSON.parse(localStorage.getItem("authentication")); - headers["jwt_token"] = authentication.jwt_token; - } - headers = { - "X-API-KEY": configConstants.API_KEY, - ...headers, - } - } + // if (localStorage.getItem("authentication")) { + // let authentication = JSON.parse(localStorage.getItem("authentication")); + // headers["jwt_token"] = authentication.jwt_token; + // } + // } else { + // if (localStorage.getItem("authentication")) { + // let authentication = JSON.parse(localStorage.getItem("authentication")); + // headers["jwt_token"] = authentication.jwt_token; + // } + // headers = { + // "X-API-KEY": configConstants.API_KEY, + // ...headers, + // } + // } if (isLoading) { $(".loading").removeClass("hide"); } @@ -43,10 +44,10 @@ export function apiCaller( method, timeout: configConstants.API_TIMEOUT, url: `${basUrl}${endpoint}`, - auth: { - username: configConstants.AUTH_BASIC_USER_NAME, - password: configConstants.AUTH_BASIC_PASSWORD, - }, + // auth: { + // username: configConstants.AUTH_BASIC_USER_NAME, + // password: configConstants.AUTH_BASIC_PASSWORD, + // }, data: body, headers: headers, })