parent
93d23e5229
commit
7b348d6879
11 changed files with 516 additions and 42 deletions
@ -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; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -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 ( |
||||
<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 16 16"><path fill="#404041" fill-rule="evenodd" d="M0 2.965C0 1.88.88 1 1.965 1h2.807c1.085 0 1.965.88 1.965 1.965v.561c0 1.086-.88 1.965-1.965 1.965H1.965A1.965 1.965 0 0 1 0 3.526zm1.965-.28a.28.28 0 0 0-.28.28v.561a.28.28 0 0 0 .28.281h2.807a.28.28 0 0 0 .28-.28v-.562a.28.28 0 0 0-.28-.28zm6.175.561c0-.465.377-.842.842-.842h6.176a.842.842 0 1 1 0 1.684H8.982a.842.842 0 0 1-.842-.842M.28 8.298c0-.465.378-.842.843-.842H11.79a.842.842 0 1 1 0 1.684H1.123a.842.842 0 0 1-.842-.842M.28 13.35c0-.464.378-.841.843-.841h13.474a.842.842 0 1 1 0 1.684H1.123a.842.842 0 0 1-.842-.842" clip-rule="evenodd"/><path fill="#404041" d="M14.877 9.14a.842.842 0 1 0 0-1.684a.842.842 0 0 0 0 1.684"/></svg> |
||||
) |
||||
} |
||||
|
||||
const renderIconDate = () => { |
||||
return ( |
||||
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 36 36"><path fill="#404041" d="M32.25 6H29v2h3v22H4V8h3V6H3.75A1.78 1.78 0 0 0 2 7.81v22.38A1.78 1.78 0 0 0 3.75 32h28.5A1.78 1.78 0 0 0 34 30.19V7.81A1.78 1.78 0 0 0 32.25 6" class="clr-i-outline clr-i-outline-path-1"/><path fill="#404041" d="M8 14h2v2H8z" class="clr-i-outline clr-i-outline-path-2"/><path fill="#404041" d="M14 14h2v2h-2z" class="clr-i-outline clr-i-outline-path-3"/><path fill="#404041" d="M20 14h2v2h-2z" class="clr-i-outline clr-i-outline-path-4"/><path fill="#404041" d="M26 14h2v2h-2z" class="clr-i-outline clr-i-outline-path-5"/><path fill="#404041" d="M8 19h2v2H8z" class="clr-i-outline clr-i-outline-path-6"/><path fill="#404041" d="M14 19h2v2h-2z" class="clr-i-outline clr-i-outline-path-7"/><path fill="#404041" d="M20 19h2v2h-2z" class="clr-i-outline clr-i-outline-path-8"/><path fill="#404041" d="M26 19h2v2h-2z" class="clr-i-outline clr-i-outline-path-9"/><path fill="#404041" d="M8 24h2v2H8z" class="clr-i-outline clr-i-outline-path-10"/><path fill="#404041" d="M14 24h2v2h-2z" class="clr-i-outline clr-i-outline-path-11"/><path fill="#404041" d="M20 24h2v2h-2z" class="clr-i-outline clr-i-outline-path-12"/><path fill="#404041" d="M26 24h2v2h-2z" class="clr-i-outline clr-i-outline-path-13"/><path fill="#404041" d="M10 10a1 1 0 0 0 1-1V3a1 1 0 0 0-2 0v6a1 1 0 0 0 1 1" class="clr-i-outline clr-i-outline-path-14"/><path fill="#404041" d="M26 10a1 1 0 0 0 1-1V3a1 1 0 0 0-2 0v6a1 1 0 0 0 1 1" class="clr-i-outline clr-i-outline-path-15"/><path fill="#404041" d="M13 6h10v2H13z" class="clr-i-outline clr-i-outline-path-16"/><path fill="none" d="M0 0h36v36H0z"/></svg> |
||||
) |
||||
} |
||||
|
||||
return ( |
||||
<div className="bg-main rel"> |
||||
<HeaderMain /> |
||||
<div className="body-home-container"> |
||||
<div className="sunE-container"> |
||||
<div className="main-container"> |
||||
<div className="filter-container"> |
||||
<div className="filter-form"> |
||||
<div className="keyword-filter-form"> |
||||
<InputText |
||||
classNameContainer='input-container' |
||||
className='input-base-filter' |
||||
value={filter.keyword} |
||||
setValue={(text) => changeFilter('keyword', text)} |
||||
type="text" |
||||
name="keyword" |
||||
placeholder="Nhập tên / số điện thoại / email" |
||||
autoFocus={true} |
||||
renderLabelIcon={renderIconKeyWord} |
||||
/> |
||||
</div> |
||||
<div className="date-filter-form"> |
||||
<InputDate |
||||
classNameContainer='input-container' |
||||
className='input-base-filter' |
||||
value={filter.start_date} |
||||
setValue={(date) => changeFilter('start_date', date)} |
||||
name="start_date" |
||||
renderLabelIcon={renderIconDate} |
||||
placeholder={"Từ ngày"} |
||||
maxDate={new Date()} |
||||
/> |
||||
<InputDate |
||||
classNameContainer='input-container' |
||||
className='input-base-filter' |
||||
value={filter.end_date} |
||||
setValue={(date) => changeFilter('end_date', date)} |
||||
name="end_date" |
||||
renderLabelIcon={renderIconDate} |
||||
placeholder={"Đến ngày"} |
||||
maxDate={new Date()} |
||||
/> |
||||
</div> |
||||
</div> |
||||
<div className="filter-action"> |
||||
<button className="btn-cancel-filter btn-filter" onClick={handleCancelFilter} disabled={!isFilter}> |
||||
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24"><path fill="#4b4a4a" d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10s10-4.47 10-10S17.53 2 12 2m0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8s8 3.59 8 8s-3.59 8-8 8m3.59-13L12 10.59L8.41 7L7 8.41L10.59 12L7 15.59L8.41 17L12 13.41L15.59 17L17 15.59L13.41 12L17 8.41z"/></svg> |
||||
Hủy |
||||
</button> |
||||
<button className="btn-line-blue btn-filter" onClick={handleFilter} disabled={!validateFilter()}> |
||||
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24"><g fill="none" fill-rule="evenodd"><path d="M24 0v24H0V0zM12.593 23.258l-.011.002l-.071.035l-.02.004l-.014-.004l-.071-.035q-.016-.005-.024.005l-.004.01l-.017.428l.005.02l.01.013l.104.074l.015.004l.012-.004l.104-.074l.012-.016l.004-.017l-.017-.427q-.004-.016-.017-.018m.265-.113l-.013.002l-.185.093l-.01.01l-.003.011l.018.43l.005.012l.008.007l.201.093q.019.005.029-.008l.004-.014l-.034-.614q-.005-.019-.02-.022m-.715.002a.02.02 0 0 0-.027.006l-.006.014l-.034.614q.001.018.017.024l.015-.002l.201-.093l.01-.008l.004-.011l.017-.43l-.003-.012l-.01-.01z"/><path fill="#ffffff" d="M10.5 2a8.5 8.5 0 1 0 5.262 15.176l3.652 3.652a1 1 0 0 0 1.414-1.414l-3.652-3.652A8.5 8.5 0 0 0 10.5 2M4 10.5a6.5 6.5 0 1 1 13 0a6.5 6.5 0 0 1-13 0"/></g></svg> |
||||
Tìm kiếm |
||||
</button> |
||||
</div> |
||||
</div> |
||||
|
||||
<div className="list-customer-container"> |
||||
{!!listCustomer.length && <p className="total-customer">{`Tổng số khách hàng: ${listCustomer.length}`}</p>} |
||||
<div className="list-customer"> |
||||
{listCustomer?.map(item => ( |
||||
<div className="customer-item" key={item?.id}> |
||||
<p className="customer-name">{item?.guest_name}</p> |
||||
<div className="customer-row customer-row-mobile"> |
||||
<div className="customer-info"> |
||||
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 256 256"><path fill="#00B9B7" d="m224 154.8l-47.09-21.11l-.18-.08a19.94 19.94 0 0 0-19 1.75a13 13 0 0 0-1.12.84l-22.31 19c-13-7.05-26.43-20.37-33.49-33.21l19.06-22.66a12 12 0 0 0 .85-1.15a20 20 0 0 0 1.66-18.83a1.4 1.4 0 0 1-.08-.18L101.2 32a20.06 20.06 0 0 0-20.78-11.85A60.27 60.27 0 0 0 28 80c0 81.61 66.39 148 148 148a60.27 60.27 0 0 0 59.85-52.42A20.06 20.06 0 0 0 224 154.8M176 204A124.15 124.15 0 0 1 52 80a36.29 36.29 0 0 1 28.48-35.54l18.82 42l-19.16 22.82a12 12 0 0 0-.86 1.16A20 20 0 0 0 78 130.08c9.42 19.28 28.83 38.56 48.31 48a20 20 0 0 0 19.69-1.45a12 12 0 0 0 1.11-.85l22.43-19.07l42 18.81A36.29 36.29 0 0 1 176 204"/></svg> |
||||
<span>{item?.phone}</span> |
||||
</div> |
||||
<div className="customer-info"> |
||||
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 24 24"><path fill="#00B9B7" d="M22 6c0-1.1-.9-2-2-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2zm-2 0l-8 5l-8-5zm0 12H4V8l8 5l8-5z"/></svg> |
||||
<span>{item?.email}</span> |
||||
</div> |
||||
</div> |
||||
<div className="customer-row"> |
||||
<div className="customer-info"> |
||||
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 24 24"><path fill="#00B9B7" d="M21 10.12h-6.78l2.74-2.82c-2.73-2.7-7.15-2.8-9.88-.1a6.887 6.887 0 0 0 0 9.8c2.73 2.7 7.15 2.7 9.88 0c1.36-1.35 2.04-2.92 2.04-4.9h2c0 1.98-.88 4.55-2.64 6.29c-3.51 3.48-9.21 3.48-12.72 0c-3.5-3.47-3.53-9.11-.02-12.58a8.987 8.987 0 0 1 12.65 0L21 3zM12.5 8v4.25l3.5 2.08l-.72 1.21L11 13V8z"/></svg> |
||||
<span>{dayjs(item?.date_receive).format('DD/MM/YYYY')}</span> |
||||
</div> |
||||
{!!item?.grade && <div className="customer-info"> |
||||
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 32 32"><path fill="#00B9B7" d="m16 7.78l-.313.095l-12.5 4.188L.345 13L2 13.53v8.75c-.597.347-1 .98-1 1.72a2 2 0 1 0 4 0c0-.74-.403-1.373-1-1.72v-8.06l2 .655V20c0 .82.5 1.5 1.094 1.97c.594.467 1.332.797 2.218 1.093c1.774.59 4.112.937 6.688.937c2.576 0 4.914-.346 6.688-.938c.886-.295 1.624-.625 2.218-1.093C25.5 21.5 26 20.82 26 20v-5.125l2.813-.938L31.655 13l-2.843-.938l-12.5-4.187zm0 2.095L25.375 13L16 16.125L6.625 13zm-8 5.688l7.688 2.562l.312.094l.313-.095L24 15.562V20c0 .01.004.126-.313.375c-.316.25-.883.565-1.625.813C20.58 21.681 18.395 22 16 22c-2.395 0-4.58-.318-6.063-.813c-.74-.247-1.308-.563-1.624-.812C7.995 20.125 8 20.01 8 20z"/></svg> |
||||
<span>{`Lớp ${item?.grade}`}</span> |
||||
</div>} |
||||
</div> |
||||
{item?.message && <div className="customer-row customer-row-mobile message"> |
||||
<div className="customer-info"> |
||||
<svg xmlns="http://www.w3.org/2000/svg" width="30" height="30" viewBox="0 0 24 24"><path fill="#00B9B7" d="M4 4h16v12H5.17L4 17.17zm0-2c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm2 10h12v2H6zm0-3h12v2H6zm0-3h12v2H6z"/></svg> |
||||
<span>{item?.message}</span> |
||||
</div> |
||||
</div>} |
||||
</div> |
||||
))} |
||||
</div> |
||||
{!listCustomer.length && !isLoading && <p className="empty-text">Không có dữ liệu.</p>} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
) |
||||
} |
Loading…
Reference in new issue