change list invoce and tickets + pwa + ...
This commit is contained in:
@@ -0,0 +1 @@
|
|||||||
|
if('serviceWorker' in navigator) navigator.serviceWorker.register('/dev-sw.js?dev-sw', { scope: '/', type: 'classic' })
|
||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2018 Google Inc. All Rights Reserved.
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// If the loader is already loaded, just stop.
|
||||||
|
if (!self.define) {
|
||||||
|
let registry = {};
|
||||||
|
|
||||||
|
// Used for `eval` and `importScripts` where we can't get script URL by other means.
|
||||||
|
// In both cases, it's safe to use a global var because those functions are synchronous.
|
||||||
|
let nextDefineUri;
|
||||||
|
|
||||||
|
const singleRequire = (uri, parentUri) => {
|
||||||
|
uri = new URL(uri + ".js", parentUri).href;
|
||||||
|
return registry[uri] || (
|
||||||
|
|
||||||
|
new Promise(resolve => {
|
||||||
|
if ("document" in self) {
|
||||||
|
const script = document.createElement("script");
|
||||||
|
script.src = uri;
|
||||||
|
script.onload = resolve;
|
||||||
|
document.head.appendChild(script);
|
||||||
|
} else {
|
||||||
|
nextDefineUri = uri;
|
||||||
|
importScripts(uri);
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
.then(() => {
|
||||||
|
let promise = registry[uri];
|
||||||
|
if (!promise) {
|
||||||
|
throw new Error(`Module ${uri} didn’t register its module`);
|
||||||
|
}
|
||||||
|
return promise;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
self.define = (depsNames, factory) => {
|
||||||
|
const uri = nextDefineUri || ("document" in self ? document.currentScript.src : "") || location.href;
|
||||||
|
if (registry[uri]) {
|
||||||
|
// Module is already loading or loaded.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let exports = {};
|
||||||
|
const require = depUri => singleRequire(depUri, uri);
|
||||||
|
const specialDeps = {
|
||||||
|
module: { uri },
|
||||||
|
exports,
|
||||||
|
require
|
||||||
|
};
|
||||||
|
registry[uri] = Promise.all(depsNames.map(
|
||||||
|
depName => specialDeps[depName] || require(depName)
|
||||||
|
)).then(deps => {
|
||||||
|
factory(...deps);
|
||||||
|
return exports;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
define(['./workbox-e7681877'], (function (workbox) { 'use strict';
|
||||||
|
|
||||||
|
self.skipWaiting();
|
||||||
|
workbox.clientsClaim();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The precacheAndRoute() method efficiently caches and responds to
|
||||||
|
* requests for URLs in the manifest.
|
||||||
|
* See https://goo.gl/S9QRab
|
||||||
|
*/
|
||||||
|
workbox.precacheAndRoute([{
|
||||||
|
"url": "registerSW.js",
|
||||||
|
"revision": "3ca0b8505b4bec776b69afdba2768812"
|
||||||
|
}, {
|
||||||
|
"url": "index.html",
|
||||||
|
"revision": "0.uhatus1rmk"
|
||||||
|
}], {});
|
||||||
|
workbox.cleanupOutdatedCaches();
|
||||||
|
workbox.registerRoute(new workbox.NavigationRoute(workbox.createHandlerBoundToURL("index.html"), {
|
||||||
|
allowlist: [/^\/$/]
|
||||||
|
}));
|
||||||
|
workbox.registerRoute(/^https:\/\/console\.danakcorp\.com\//, new workbox.NetworkFirst({
|
||||||
|
"cacheName": "api-cache",
|
||||||
|
"networkTimeoutSeconds": 10,
|
||||||
|
plugins: [new workbox.ExpirationPlugin({
|
||||||
|
maxEntries: 50,
|
||||||
|
maxAgeSeconds: 86400
|
||||||
|
})]
|
||||||
|
}), 'GET');
|
||||||
|
|
||||||
|
}));
|
||||||
File diff suppressed because it is too large
Load Diff
Generated
+3876
-158
File diff suppressed because it is too large
Load Diff
@@ -33,6 +33,7 @@
|
|||||||
"react-toastify": "^11.0.2",
|
"react-toastify": "^11.0.2",
|
||||||
"swiper": "^11.2.1",
|
"swiper": "^11.2.1",
|
||||||
"tailwind-merge": "^2.5.5",
|
"tailwind-merge": "^2.5.5",
|
||||||
|
"vite-plugin-pwa": "^0.21.1",
|
||||||
"yup": "^1.6.1",
|
"yup": "^1.6.1",
|
||||||
"zustand": "^5.0.2"
|
"zustand": "^5.0.2"
|
||||||
},
|
},
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 7.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
+13
-1
@@ -1 +1,13 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
<svg width="39" height="54" viewBox="0 0 39 54" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M31.1559 34.8412C31.1559 34.8412 24.6651 41.094 19.2416 46.3804V53.5924C18.6935 54.0179 38.4905 34.8845 38.4905 34.8845L19.2416 14.6909V22.3573L31.1559 34.8412Z" fill="#1D1D1B"/>
|
||||||
|
<path d="M19.1479 39.0818L0 18.643L0.237992 18.405L19.3931 38.8583L19.1479 39.0818Z" fill="#1D1D1B"/>
|
||||||
|
<path d="M19.1407 37.1635L1.75977 18.6719L1.99776 18.4412L19.3787 36.9399L19.1407 37.1635Z" fill="#1D1D1B"/>
|
||||||
|
<path d="M19.1334 35.2523L3.52661 18.708L3.7574 18.47L19.3786 35.0215L19.1334 35.2523Z" fill="#1D1D1B"/>
|
||||||
|
<path d="M19.1262 33.3337L5.28638 18.7366L5.50995 18.5059L19.3714 33.1029L19.1262 33.3337Z" fill="#1D1D1B"/>
|
||||||
|
<path d="M19.1191 31.4155L7.05347 18.7729L7.26982 18.5349L19.3571 31.1848L19.1191 31.4155Z" fill="#1D1D1B"/>
|
||||||
|
<path d="M0.375071 18.7368L0.144287 18.4988L19.1407 0L19.3715 0.237996L0.375071 18.7368Z" fill="#1D1D1B"/>
|
||||||
|
<path d="M2.15645 18.7442L1.91846 18.5134L19.1263 1.73828L19.3571 1.97628L2.15645 18.7442Z" fill="#1D1D1B"/>
|
||||||
|
<path d="M3.93049 18.7587L3.69971 18.5279L19.1117 3.48364L19.3425 3.71443L3.93049 18.7587Z" fill="#1D1D1B"/>
|
||||||
|
<path d="M5.71187 18.7658L5.47388 18.5422L19.0973 5.22168L19.3281 5.45968L5.71187 18.7658Z" fill="#1D1D1B"/>
|
||||||
|
<path d="M7.49326 18.7799L7.24805 18.5564L19.0901 6.95947L19.3137 7.19747L7.49326 18.7799Z" fill="#1D1D1B"/>
|
||||||
|
</svg>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.3 KiB |
+2
-1
@@ -427,7 +427,8 @@
|
|||||||
"approved": "تایید شده",
|
"approved": "تایید شده",
|
||||||
"APPROVED": "تایید شده",
|
"APPROVED": "تایید شده",
|
||||||
"pending": "در انتظار",
|
"pending": "در انتظار",
|
||||||
"since": "از تاریخ"
|
"since": "از تاریخ",
|
||||||
|
"to": "تا تاریخ"
|
||||||
},
|
},
|
||||||
"edit": "ویرایش",
|
"edit": "ویرایش",
|
||||||
"transaction": {
|
"transaction": {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import { Element3, Messages3, NotificationStatus, People, Receipt2 } from 'iconsax-react'
|
import { Element3, Messages3, NotificationStatus, People, Receipt2 } from 'iconsax-react'
|
||||||
import ItemDashboard from './components/ItemDashboard'
|
import ItemDashboard from './components/ItemDashboard'
|
||||||
import { useGetDashboard } from './hooks/useHomeData'
|
import { useGetDashboard } from './hooks/useHomeData'
|
||||||
|
import { Pages } from '../../config/Pages'
|
||||||
|
|
||||||
|
|
||||||
const Home: FC = () => {
|
const Home: FC = () => {
|
||||||
@@ -21,6 +22,7 @@ const Home: FC = () => {
|
|||||||
color='#00D16C'
|
color='#00D16C'
|
||||||
count={getDashboard.data?.data?.danakServicesCount}
|
count={getDashboard.data?.data?.danakServicesCount}
|
||||||
description={t('home.service')}
|
description={t('home.service')}
|
||||||
|
to={Pages.services.list}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ItemDashboard
|
<ItemDashboard
|
||||||
@@ -29,6 +31,7 @@ const Home: FC = () => {
|
|||||||
color='#00D16C'
|
color='#00D16C'
|
||||||
count={getDashboard.data?.data?.customersCount}
|
count={getDashboard.data?.data?.customersCount}
|
||||||
description={t('home.customer')}
|
description={t('home.customer')}
|
||||||
|
to={Pages.customers.list}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ItemDashboard
|
<ItemDashboard
|
||||||
@@ -37,6 +40,7 @@ const Home: FC = () => {
|
|||||||
color='#FF7B00'
|
color='#FF7B00'
|
||||||
count={getDashboard.data?.data?.unreadTickets}
|
count={getDashboard.data?.data?.unreadTickets}
|
||||||
description={t('home.unread_messages')}
|
description={t('home.unread_messages')}
|
||||||
|
to={Pages.ticket.list}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ItemDashboard
|
<ItemDashboard
|
||||||
@@ -45,6 +49,7 @@ const Home: FC = () => {
|
|||||||
color='#FF0000'
|
color='#FF0000'
|
||||||
count={getDashboard.data?.data?.adsCount}
|
count={getDashboard.data?.data?.adsCount}
|
||||||
description={t('home.active_ads')}
|
description={t('home.active_ads')}
|
||||||
|
to={Pages.ads.list}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ItemDashboard
|
<ItemDashboard
|
||||||
@@ -53,6 +58,7 @@ const Home: FC = () => {
|
|||||||
color='#0047FF'
|
color='#0047FF'
|
||||||
count={getDashboard.data?.data?.invoicesCount}
|
count={getDashboard.data?.data?.invoicesCount}
|
||||||
description={t('home.new_invoice')}
|
description={t('home.new_invoice')}
|
||||||
|
to={Pages.receipts.index}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
import { FC, ReactNode } from 'react'
|
import { FC, ReactNode } from 'react'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
title: string
|
title: string
|
||||||
icon: ReactNode,
|
icon: ReactNode,
|
||||||
color: string,
|
color: string,
|
||||||
count: number,
|
count: number,
|
||||||
description: string
|
description: string,
|
||||||
|
to?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const ItemDashboard: FC<Props> = (props: Props) => {
|
const ItemDashboard: FC<Props> = (props: Props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='p-6 min-w-[40%] xl:min-w-[15%] flex flex-col items-center xl:items-start flex-1 h-[178px] bg-white rounded-3xl'>
|
<Link to={props.to ? props.to : ''} className='p-6 min-w-[40%] xl:min-w-[15%] flex flex-col items-center xl:items-start flex-1 h-[178px] bg-white rounded-3xl'>
|
||||||
<div className='size-10 rounded-full bg-[#EEF0F7] flex justify-center items-center'>
|
<div className='size-10 rounded-full bg-[#EEF0F7] flex justify-center items-center'>
|
||||||
{props.icon}
|
{props.icon}
|
||||||
</div>
|
</div>
|
||||||
@@ -28,7 +30,7 @@ const ItemDashboard: FC<Props> = (props: Props) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ const CreateReceipt: FC = () => {
|
|||||||
<Button
|
<Button
|
||||||
className='px-5'
|
className='px-5'
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
|
isLoading={createInvoice.isPending}
|
||||||
>
|
>
|
||||||
<div className='flex gap-2 items-center'>
|
<div className='flex gap-2 items-center'>
|
||||||
<TickCircle size={20} color='white' />
|
<TickCircle size={20} color='white' />
|
||||||
|
|||||||
@@ -13,22 +13,25 @@ import Input from '../../components/Input'
|
|||||||
import { CustomerItemType } from '../customer/types/CustomerTypes'
|
import { CustomerItemType } from '../customer/types/CustomerTypes'
|
||||||
import DatePickerComponent from '../../components/DatePicker'
|
import DatePickerComponent from '../../components/DatePicker'
|
||||||
import { useSearchParams } from 'react-router-dom'
|
import { useSearchParams } from 'react-router-dom'
|
||||||
|
import moment from 'moment-jalaali'
|
||||||
|
|
||||||
const ReceiptsList: FC = () => {
|
const ReceiptsList: FC = () => {
|
||||||
|
|
||||||
const { t } = useTranslation('global')
|
const { t } = useTranslation('global')
|
||||||
const [searchParams] = useSearchParams()
|
const [searchParams] = useSearchParams()
|
||||||
const [activeTab, setActiveTab] = useState<"PENDING" | "PAID" | "CANCELED" | "EXPIRED">('PENDING')
|
const [activeTab, setActiveTab] = useState<"PENDING" | "PAID" | "CANCELLED" | "EXPIRED" | ''>('PENDING')
|
||||||
const [customerId, setCustomerId] = useState<string>('')
|
const [customerId, setCustomerId] = useState<string>('')
|
||||||
const [search, setSearch] = useState<string>('')
|
const [search, setSearch] = useState<string>('')
|
||||||
const [date, setDate] = useState<string>('')
|
const [date, setDate] = useState<string>('')
|
||||||
const getInvoices = useGetInvoices(activeTab, customerId, search, date)
|
const [endDate, setEndDate] = useState<string>('')
|
||||||
|
const getInvoices = useGetInvoices(activeTab, customerId, search, date, endDate)
|
||||||
const getCustomers = useGetCustomers()
|
const getCustomers = useGetCustomers()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const urlCustomerId = searchParams.get('user')
|
const urlCustomerId = searchParams.get('user')
|
||||||
if (urlCustomerId) {
|
if (urlCustomerId) {
|
||||||
setCustomerId(urlCustomerId)
|
setCustomerId(urlCustomerId)
|
||||||
|
setActiveTab('')
|
||||||
}
|
}
|
||||||
}, [searchParams])
|
}, [searchParams])
|
||||||
|
|
||||||
@@ -55,12 +58,19 @@ const ReceiptsList: FC = () => {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<DatePickerComponent
|
<DatePickerComponent
|
||||||
onChange={(date) => setDate(date)}
|
onChange={(date) => setDate(moment(date, 'jYYYY-jMM-jDD').format('YYYY-MM-DD'))}
|
||||||
label={t('receip.since')}
|
label={t('receip.since')}
|
||||||
className='min-w-40'
|
className='min-w-40'
|
||||||
placeholder={t('select')}
|
placeholder={t('select')}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<DatePickerComponent
|
||||||
|
onChange={(date) => setEndDate(moment(date, 'jYYYY-jMM-jDD').format('YYYY-MM-DD'))}
|
||||||
|
label={t('receip.to')}
|
||||||
|
className='min-w-40'
|
||||||
|
placeholder={t('select')}
|
||||||
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Input
|
<Input
|
||||||
@@ -87,9 +97,9 @@ const ReceiptsList: FC = () => {
|
|||||||
value: 'PAID'
|
value: 'PAID'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <CloseCircle color={activeTab === 'CANCELED' ? 'black' : '#8C90A3'} size={22} />,
|
icon: <CloseCircle color={activeTab === 'CANCELLED' ? 'black' : '#8C90A3'} size={22} />,
|
||||||
label: t('receip.canceled'),
|
label: t('receip.canceled'),
|
||||||
value: 'CANCELED'
|
value: 'CANCELLED'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: <FolderOpen color={activeTab === 'EXPIRED' ? 'black' : '#8C90A3'} size={22} />,
|
icon: <FolderOpen color={activeTab === 'EXPIRED' ? 'black' : '#8C90A3'} size={22} />,
|
||||||
@@ -97,7 +107,7 @@ const ReceiptsList: FC = () => {
|
|||||||
value: 'EXPIRED'
|
value: 'EXPIRED'
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
onChange={(value) => setActiveTab(value as "PENDING" | "PAID" | "CANCELED" | "EXPIRED")}
|
onChange={(value) => setActiveTab(value as "PENDING" | "PAID" | "CANCELLED" | "EXPIRED")}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,12 @@ export const useGetInvoices = (
|
|||||||
status: string,
|
status: string,
|
||||||
customerId: string,
|
customerId: string,
|
||||||
search: string,
|
search: string,
|
||||||
date: string
|
date: string,
|
||||||
|
endDate: string
|
||||||
) => {
|
) => {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: ["invoices", status, customerId, search, date],
|
queryKey: ["invoices", status, customerId, search, date, endDate],
|
||||||
queryFn: () => api.getInvoces(status, customerId, search, date),
|
queryFn: () => api.getInvoces(status, customerId, search, date, endDate),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,12 +5,16 @@ export const getInvoces = async (
|
|||||||
status: string,
|
status: string,
|
||||||
customerId: string,
|
customerId: string,
|
||||||
search: string,
|
search: string,
|
||||||
date: string
|
date: string,
|
||||||
|
endDate: string
|
||||||
) => {
|
) => {
|
||||||
let query = `status=${status}`;
|
const params = new URLSearchParams();
|
||||||
if (customerId) query += `&userId=${customerId}`;
|
if (status) params.append("status", status);
|
||||||
if (search) query += `&q=${search}`;
|
if (customerId) params.append("userId", customerId);
|
||||||
if (date) query += `&date=${date}`;
|
if (search) params.append("q", search);
|
||||||
|
if (date) params.append("since", date);
|
||||||
|
if (endDate) params.append("to", endDate);
|
||||||
|
const query = params.toString();
|
||||||
const { data } = await axios.get(`/invoices?${query}`);
|
const { data } = await axios.get(`/invoices?${query}`);
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,6 +26,6 @@ export type ReceiptItemType = {
|
|||||||
lastName: string;
|
lastName: string;
|
||||||
};
|
};
|
||||||
dueDate: string;
|
dueDate: string;
|
||||||
status: "PENDING" | "PAID" | "CANCELED" | "EXPIRED" | "APPROVED";
|
status: "PENDING" | "PAID" | "CANCELLED" | "EXPIRED" | "APPROVED";
|
||||||
paidAt: string;
|
paidAt: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -14,13 +14,14 @@ const TicketList: FC = () => {
|
|||||||
const { t } = useTranslation('global')
|
const { t } = useTranslation('global')
|
||||||
const [searchParams] = useSearchParams()
|
const [searchParams] = useSearchParams()
|
||||||
const [customerId, setCustomerId] = useState<string>('')
|
const [customerId, setCustomerId] = useState<string>('')
|
||||||
const [activeTab, setActiveTab] = useState<'ANSWERED' | 'PENDING' | 'CLOSED'>('PENDING')
|
const [activeTab, setActiveTab] = useState<'ANSWERED' | 'PENDING' | 'CLOSED' | ''>('PENDING')
|
||||||
const getTicket = useGetTickets(activeTab, customerId)
|
const getTicket = useGetTickets(activeTab, customerId)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const urlCustomerId = searchParams.get('user')
|
const urlCustomerId = searchParams.get('user')
|
||||||
if (urlCustomerId) {
|
if (urlCustomerId) {
|
||||||
setCustomerId(urlCustomerId)
|
setCustomerId(urlCustomerId)
|
||||||
|
setActiveTab('')
|
||||||
}
|
}
|
||||||
}, [searchParams])
|
}, [searchParams])
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ import axios from "../../../config/axios";
|
|||||||
import { AddMessageTicketType, CreateCategoryType } from "../types/TicketTypes";
|
import { AddMessageTicketType, CreateCategoryType } from "../types/TicketTypes";
|
||||||
|
|
||||||
export const getTickets = async (status: string, customerId?: string) => {
|
export const getTickets = async (status: string, customerId?: string) => {
|
||||||
let query = `/tickets/admin?status=${status}`;
|
const params = new URLSearchParams();
|
||||||
if (customerId) {
|
if (status) params.append("status", status);
|
||||||
query += `&userId=${customerId}`;
|
if (customerId) params.append("userId", customerId);
|
||||||
}
|
const query = params.toString();
|
||||||
const { data } = await axios.get(query);
|
const { data } = await axios.get(`/tickets/admin?${query}`);
|
||||||
return data;
|
return data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+46
-3
@@ -1,10 +1,53 @@
|
|||||||
import { defineConfig } from "vite";
|
import { defineConfig } from "vite";
|
||||||
import react from "@vitejs/plugin-react";
|
import react from "@vitejs/plugin-react";
|
||||||
|
import { VitePWA } from "vite-plugin-pwa";
|
||||||
|
|
||||||
// https://vite.dev/config/
|
// https://vite.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [
|
||||||
define: {
|
react(),
|
||||||
global: "window", // تعریف `global` برای مرورگر
|
VitePWA({
|
||||||
|
registerType: "autoUpdate",
|
||||||
|
devOptions: {
|
||||||
|
enabled: true, // در حالت توسعه هم کار کند
|
||||||
},
|
},
|
||||||
|
manifest: {
|
||||||
|
name: "Danak Panel Admin",
|
||||||
|
short_name: "Danak Panel Admin",
|
||||||
|
description: "Danak Panel Admin",
|
||||||
|
theme_color: "#ffffff",
|
||||||
|
background_color: "#ffffff",
|
||||||
|
display: "standalone",
|
||||||
|
start_url: "/dashboard", // صفحه اصلی PWA
|
||||||
|
icons: [
|
||||||
|
{
|
||||||
|
src: "/icon-192x192.png",
|
||||||
|
sizes: "192x192",
|
||||||
|
type: "image/png",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
src: "/icon-512x512.png",
|
||||||
|
sizes: "512x512",
|
||||||
|
type: "image/png",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
workbox: {
|
||||||
|
runtimeCaching: [
|
||||||
|
{
|
||||||
|
urlPattern: /^https:\/\/console\.danakcorp\.com\//,
|
||||||
|
handler: "NetworkFirst",
|
||||||
|
options: {
|
||||||
|
cacheName: "api-cache",
|
||||||
|
expiration: {
|
||||||
|
maxEntries: 50,
|
||||||
|
maxAgeSeconds: 60 * 60 * 24,
|
||||||
|
},
|
||||||
|
networkTimeoutSeconds: 10,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
],
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user