Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 77c01683ae | |||
| 14f9b83f12 | |||
| b31650e5f7 | |||
| e508e7cffa | |||
| 79ff004077 | |||
| 175e6b5434 | |||
| 9b3cb2a75a | |||
| b142833901 | |||
| 10a6023ceb | |||
| d37026c868 | |||
| bd4cdb1ae9 | |||
| f86e5abd3d | |||
| 50551f1c7d | |||
| a87a0a58db | |||
| 6927d53c59 | |||
| e24df8e744 | |||
| 20c224b625 | |||
| 54a0361620 | |||
| a9721991de | |||
| e15e9f271c | |||
| c9ad818370 | |||
| 466d10c0fc | |||
| 7a7149de0c | |||
| 34ef37c905 | |||
| 52249ae3a2 | |||
| 183a6ce903 | |||
| e65371e41b | |||
| 767a900e36 | |||
| 8f41dcbf35 | |||
| 11289c44fb | |||
| 65f4aafc68 | |||
| 79d5005d6b | |||
| ba6b3a1dd0 | |||
| ec1402f610 | |||
| 4481dae24e | |||
| 68eb0f9abc | |||
| b5a5452a0d | |||
| 0a66679950 | |||
| fd9eb08cea | |||
| 1e28046093 | |||
| 4b39b73931 | |||
| 54bfe7affa | |||
| d7cfb03550 |
@@ -9,7 +9,9 @@ const RouteLinks = {
|
||||
recentSignup: '/recent-signup',
|
||||
loansPage: '/loans',
|
||||
transactionsPage: '/transactions',
|
||||
countrySettings: '/country',
|
||||
products: '/products',
|
||||
productView: '/product-view/*',
|
||||
usersAdmin: '/users-admin',
|
||||
productTemplates: '/products-template',
|
||||
customTemplates: '/custom-template',
|
||||
|
||||
+5
-1
@@ -20,7 +20,9 @@ import TransactionDetailsPage from './pages/TransactionDetailsPage'
|
||||
import AccountDetailsPage from "./pages/AccountDetailsPage";
|
||||
import ProductTemplatePage from "./pages/ProductTemplatePage";
|
||||
import CustomTemplatePage from "./pages/CustomTemplatePage";
|
||||
import SubscriptionDetailsPage from "./pages/SubscriptionDetailsPage"; // TRANSACTION DETAILS PAGE
|
||||
import SubscriptionDetailsPage from "./pages/SubscriptionDetailsPage";
|
||||
import CountrySettingsPage from "./pages/CountrySettingsPage";
|
||||
import ProductViewPage from "./pages/ProductViewPage"; // TRANSACTION DETAILS PAGE
|
||||
|
||||
|
||||
// const Home = lazy(() => import('./pages/Home'));
|
||||
@@ -38,8 +40,10 @@ export default function SiteRoutes() {
|
||||
<Route path={RouteLinks.accountDetails} element={<AccountDetailsPage/>}/> {`*/CUSTOMER PAGE*/`}
|
||||
<Route path={RouteLinks.billings} element={<BillingsPage/>}/> {`*/BILLINGS PAGE*/`}
|
||||
<Route path={RouteLinks.products} element={<ProductsPage/>}/> {`*/PRODUCTS PAGE*/`}
|
||||
<Route path={RouteLinks.productView} element={<ProductViewPage/>}/> {`*/PRODUCTS VIEW PAGE*/`}
|
||||
<Route path={RouteLinks.usersAdmin} element={<UsersAdminPage/>}/> {`*/ADMIN USERS PAGE*/`}
|
||||
|
||||
<Route path={RouteLinks.countrySettings} element={<CountrySettingsPage/>}/> {`*/PRODUCTS TEMPLATE PAGE*/`}
|
||||
<Route path={RouteLinks.productTemplates} element={<ProductTemplatePage/>}/> {`*/PRODUCTS TEMPLATE PAGE*/`}
|
||||
<Route path={RouteLinks.customTemplates} element={<CustomTemplatePage/>}/> {`*/CUSTOM TEMPLATES PAGE*/`}
|
||||
|
||||
|
||||
@@ -1,52 +1,61 @@
|
||||
|
||||
|
||||
|
||||
export default function AccountProfileView() {
|
||||
export default function AccountProfileView({profile}) {
|
||||
return <>
|
||||
<div className="row" style={{paddingBottom:'20px'}}>
|
||||
<div className="col-12 col-lg-12">
|
||||
<div className="card card-statistics">
|
||||
<div className="card-header">
|
||||
<div className="card-heading">
|
||||
<h4 className="card-title"><b>Account Profile</b></h4>
|
||||
</div>
|
||||
<div className="pb-5">
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="w-full">
|
||||
<h4 className="font-semibold text-lg">Account Profile</h4>
|
||||
</div>
|
||||
<div className="card-body">
|
||||
<div className="table-responsive">
|
||||
<table className="table table-hover mb-0" style={{width:'100%', backgroundColor: 'aliceblue', borderRadius: '10px'}}>
|
||||
<thead>
|
||||
<div className="w-full overflow-x-auto">
|
||||
<>
|
||||
<table className="py-2 w-full text-sm bg-[aliceblue] dark:bg-transparent rounded-[10px]">
|
||||
<thead className="py-2 text-sm text-slate-500 text-left">
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th scope="col">First</th>
|
||||
<th scope="col">Last</th>
|
||||
<th scope="col">Handle</th>
|
||||
|
||||
<th scope="col" className="px-2 py-2">
|
||||
Member ID
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
Practice/specialization
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
URL Name
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">1</th>
|
||||
<td>Mark</td>
|
||||
<td>Otto</td>
|
||||
<td>@mdo</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">2</th>
|
||||
<td>Jacob</td>
|
||||
<td>Thornton</td>
|
||||
<td>@fat</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">3</th>
|
||||
<td>Larry</td>
|
||||
<td>the Bird</td>
|
||||
<td>@twitter</td>
|
||||
</tr>
|
||||
{(profile && Object.keys(profile).length > 0) ?
|
||||
<tr className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{profile?.member_id}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">Practice: {profile?.practice}</div>
|
||||
<div className="text-base font-semibold">Specialization: {profile?.specialization}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{profile?.url_name}</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
:
|
||||
<tr className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-3 py-2" colSpan={3}>
|
||||
<div className="flex justify-center items-center">
|
||||
No Record Found
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</>
|
||||
}
|
||||
@@ -14,12 +14,12 @@ import CustomerPaymentsView from "./CustomerPaymentsView";
|
||||
|
||||
export default function AccountViewCom() {
|
||||
|
||||
const {state:{memberUID}} = useLocation()
|
||||
const {state} = useLocation()
|
||||
const navigate = useNavigate()
|
||||
|
||||
useEffect(()=>{
|
||||
if(!memberUID){
|
||||
navigate(RouteLinks.customerPage, {replace: true})
|
||||
if(!state?.memberUID){
|
||||
navigate(RouteLinks.homePage, {replace: true})
|
||||
}
|
||||
},[])
|
||||
|
||||
@@ -28,7 +28,7 @@ export default function AccountViewCom() {
|
||||
queryFn: () => {
|
||||
// const filterData = filter?.type ? {[filter?.type]: filter.id} : {}
|
||||
const reqData = {
|
||||
member_uid: memberUID
|
||||
member_uid: state?.memberUID
|
||||
// page,
|
||||
// ...filterData
|
||||
}
|
||||
@@ -45,7 +45,7 @@ export default function AccountViewCom() {
|
||||
|
||||
return (
|
||||
<div className='w-full flex flex-col gap-8'>
|
||||
<BreadcrumbCom title={`Account View [${memberUID}]`} paths={['Dashboard', 'Account View']}/>
|
||||
<BreadcrumbCom title={`Account View [${state?.memberUID}]`} paths={['Dashboard', 'Account View']}/>
|
||||
|
||||
<div className='box bg-white dark:bg-black-box text-black-body dark:text-white-body'>
|
||||
{isFetching ?
|
||||
@@ -57,8 +57,8 @@ export default function AccountViewCom() {
|
||||
:
|
||||
<>
|
||||
<CustomerAccountView accountInfo={account_info} />
|
||||
<AccountProfileView />
|
||||
<CustomerSubscriptionsView subscriptions={subscriptions} memberUID={memberUID} />
|
||||
<AccountProfileView profile={account_profile} />
|
||||
<CustomerSubscriptionsView subscriptions={subscriptions} />
|
||||
<CustomerPaymentsView payments={payments} />
|
||||
</>
|
||||
|
||||
|
||||
@@ -10,13 +10,11 @@ export default function CustomerAccountView({accountInfo}) {
|
||||
</div>
|
||||
<div className="w-full overflow-x-auto">
|
||||
<>
|
||||
<table className="py-2 w-full text-sm" style={{backgroundColor: 'aliceblue', borderRadius: '10px'}}>
|
||||
<table className="py-2 w-full text-sm bg-[aliceblue] dark:bg-transparent rounded-[10px]">
|
||||
<thead className="py-2 text-sm text-slate-500 text-left">
|
||||
<tr>
|
||||
|
||||
<th scope="col" className="px-2 py-2">
|
||||
#
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
Firstname
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
@@ -28,6 +26,7 @@ export default function CustomerAccountView({accountInfo}) {
|
||||
<th scope="col" className="px-2">
|
||||
Email
|
||||
</th>
|
||||
|
||||
<th scope="col" className="px-2 text-right">
|
||||
Action
|
||||
</th>
|
||||
@@ -36,11 +35,11 @@ export default function CustomerAccountView({accountInfo}) {
|
||||
<tbody>
|
||||
{(accountInfo && Object.keys(accountInfo).length > 0) ?
|
||||
<tr className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-2 py-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{1}</div>
|
||||
</div>
|
||||
</td>
|
||||
{/*<td className="px-2 py-2">*/}
|
||||
{/* <div className="text-left">*/}
|
||||
{/* <div className="text-base font-semibold">{1}</div>*/}
|
||||
{/* </div>*/}
|
||||
{/*</td>*/}
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{accountInfo?.firstname}</div>
|
||||
@@ -61,6 +60,7 @@ export default function CustomerAccountView({accountInfo}) {
|
||||
<div className="text-base font-semibold">{accountInfo?.email}</div>
|
||||
</div>
|
||||
</td>
|
||||
|
||||
<td className="px-2 text-right">
|
||||
<div className='flex items-center justify-end gap-3 md:gap-4'>
|
||||
<div
|
||||
|
||||
@@ -8,20 +8,23 @@ export default function CustomerPaymentsView({payments}) {
|
||||
</div>
|
||||
<div className="w-full overflow-x-auto">
|
||||
<>
|
||||
<table className="py-2 w-full text-sm" style={{backgroundColor: 'aliceblue', borderRadius: '10px'}}>
|
||||
<table className="py-2 w-full text-sm bg-[aliceblue] dark:bg-transparent rounded-[10px]">
|
||||
<thead className="py-2 text-sm text-slate-500 text-left">
|
||||
<tr>
|
||||
<th scope="col" className="px-2 py-2">
|
||||
#
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
First
|
||||
Added
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
Last
|
||||
Option Name
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
Handle
|
||||
Amount
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
Currency
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -35,17 +38,22 @@ export default function CustomerPaymentsView({payments}) {
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{item?.first}</div>
|
||||
<div className="text-base font-semibold">{item?.added}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{item?.last}</div>
|
||||
<div className="text-base font-semibold">{item?.option_name}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{item?.handle}</div>
|
||||
<div className="text-base font-semibold">{item?.amount}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">Dollars</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -3,7 +3,7 @@ import RouteLinks from "../../RouteLinks";
|
||||
import Icons from "../Icons";
|
||||
import {Link} from 'react-router-dom'
|
||||
|
||||
export default function CustomerSubscriptionsView({subscriptions, memberUID}) {
|
||||
export default function CustomerSubscriptionsView({subscriptions}) {
|
||||
return <>
|
||||
<div className="pb-5">
|
||||
<div className="flex flex-col gap-1">
|
||||
@@ -12,20 +12,20 @@ export default function CustomerSubscriptionsView({subscriptions, memberUID}) {
|
||||
</div>
|
||||
<div className="w-full overflow-x-auto">
|
||||
<>
|
||||
<table className="py-2 w-full text-sm" style={{backgroundColor: 'aliceblue', borderRadius: '10px'}}>
|
||||
<table className="py-2 w-full text-sm bg-[aliceblue] dark:bg-transparent rounded-[10px]">
|
||||
<thead className="py-2 text-sm text-slate-500 text-left">
|
||||
<tr>
|
||||
<th scope="col" className="px-2 py-2">
|
||||
#
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
Added
|
||||
Added/Updated
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
Product
|
||||
Product/Server
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
URL
|
||||
URL / EXT/ Templates
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
Status
|
||||
@@ -40,22 +40,46 @@ export default function CustomerSubscriptionsView({subscriptions, memberUID}) {
|
||||
<tr key={index} className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-2 py-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{index+1}</div>
|
||||
<div className="text-base font-semibold">{index + 1}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{getDateTimeFromDateString(item?.added)}</div>
|
||||
<div
|
||||
className="text-base font-semibold">{getDateTimeFromDateString(item?.added)}</div>
|
||||
<div
|
||||
className="text-base font-semibold">{getDateTimeFromDateString(item?.updated)}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{item?.product_id}</div>
|
||||
<div><a href={`http://${item?.primary_server}:${item?.provision_port}`}
|
||||
target='_blank'
|
||||
rel="noreferrer">{item?.primary_server}:{item?.provision_port}</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{item?.internal_url}</div>
|
||||
<div className="text-base">
|
||||
<span className="badge badge-pill badge-primary-inverse">
|
||||
<a href={`https://${item?.internal_url}`}
|
||||
target='_blank'
|
||||
rel="noreferrer">{item?.internal_url}</a>
|
||||
</span>
|
||||
|
||||
<br/>
|
||||
<span className="badge badge-warning">
|
||||
<a href={`https://${item?.external_url}`}
|
||||
target='_blank'
|
||||
rel="noreferrer">{item?.external_url}</a>
|
||||
</span>
|
||||
|
||||
<br/>
|
||||
<span>Template :</span> {item?.product_template}
|
||||
<br/><span>Custom :</span> {item?.custom_template}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
@@ -67,7 +91,10 @@ export default function CustomerSubscriptionsView({subscriptions, memberUID}) {
|
||||
<div className='flex items-center justify-end gap-3 md:gap-4'>
|
||||
<div
|
||||
className='p-2 flex justify-center items-center text-slate-500 bg-white-body dark:text-white-body dark:bg-black-body rounded-md'>
|
||||
<Link to={`/subscription-view/${memberUID}`} state={{customerID: item?.id, memberUID}}>
|
||||
<Link to={`/subscription-view/${item?.subscription_uid}`} state={{
|
||||
customerID: item?.id,
|
||||
subscriptionUID: item?.subscription_uid
|
||||
}}>
|
||||
<Icons name='eye'/>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query'
|
||||
import queryKeys from '../../services/queryKeys'
|
||||
import BreadcrumbCom from "../breadcrumb/BreadcrumbCom";
|
||||
import { getCountry, setCountry } from "../../services/siteServices";
|
||||
import TableWrapper from "../tableWrapper/TableWrapper";
|
||||
|
||||
export default function CountrySettings(){
|
||||
|
||||
const [selected, setSelected] = useState('')
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const {data, isFetching, status, isError, error} = useQuery({
|
||||
queryKey: queryKeys.country_list,
|
||||
queryFn: () => {
|
||||
const reqData = {
|
||||
// page,
|
||||
// ...filterData
|
||||
}
|
||||
return getCountry(reqData)
|
||||
},
|
||||
// placeholderData: (previousData, previousQuery) => previousData,
|
||||
staleTime: 0 // 0 mins
|
||||
})
|
||||
const countryData = data?.data?.country_data // COUNTRY LIST
|
||||
// console.log('countryData', countryData)
|
||||
|
||||
|
||||
const statusChange = useMutation({
|
||||
mutationFn: (fields) => {
|
||||
return setCountry(fields)
|
||||
},
|
||||
onError: (error) => {
|
||||
},
|
||||
onSuccess: (res) => {
|
||||
queryClient.refetchQueries({
|
||||
queryKey: [...queryKeys.country_list],
|
||||
// type: 'active',
|
||||
// exact: true,
|
||||
})
|
||||
},
|
||||
onSettled: () => {
|
||||
setSelected('')
|
||||
}
|
||||
})
|
||||
|
||||
//FUNCTION TO CHANGE STATUS OR SIGNUP
|
||||
const handleStatusChange = (event, details) => {
|
||||
setSelected(event.target.id)
|
||||
const name = event.target.name
|
||||
const val = name.toUpperCase() == 'STATUS' ? details.status : details.signup
|
||||
const reqData = {
|
||||
'val_type': name.toUpperCase(),
|
||||
'country_uid': details?.country_uid,
|
||||
'code': details?.code,
|
||||
'val': val == 0 ? 1 : 0
|
||||
}
|
||||
statusChange.mutate(reqData)
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='w-full flex flex-col gap-8'>
|
||||
<BreadcrumbCom title='Country Settings' paths={['Dashboard', 'Country']} />
|
||||
|
||||
<div className='relative box bg-white dark:bg-black-box text-black-body dark:text-white-body'>
|
||||
|
||||
<>
|
||||
{/* status === 'pending' */}
|
||||
{status === 'pending' ?
|
||||
<p className='text-slate-800'>Loading...</p>
|
||||
: isError ?
|
||||
<p className='text-red-500'>{error.message}</p>
|
||||
:
|
||||
// <TableWrapper data={countryData} itemsPerPage={20}>
|
||||
// {({ data }) => (
|
||||
// )}
|
||||
// </TableWrapper>
|
||||
<>
|
||||
<table className="py-2 w-full text-sm">
|
||||
<thead className="py-2 text-sm text-slate-500 text-left">
|
||||
<tr>
|
||||
<th scope="col" className="px-2 py-2">
|
||||
Code
|
||||
</th>
|
||||
<th scope="col" className="px-8">
|
||||
Country
|
||||
</th>
|
||||
<th scope="col" className="px-2 text-center">
|
||||
Status
|
||||
</th>
|
||||
<th scope="col" className="px-2 text-center">
|
||||
Signup
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{(countryData && countryData.length > 0) ? countryData?.map((item, index) => (
|
||||
<tr key={index} className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-2 py-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{item?.code}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-8">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{item?.description}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-8">
|
||||
<div className="flex justify-center">
|
||||
<>
|
||||
{selected == 'status' + index ?
|
||||
<div role="status" className="text-center">
|
||||
<svg aria-hidden="true" className="w-4 h-4 text-gray-200 animate-spin dark:text-gray-600 fill-primary" viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z" fill="currentColor"/>
|
||||
<path d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z" fill="currentFill"/>
|
||||
</svg>
|
||||
<span className="sr-only">Loading...</span>
|
||||
</div>
|
||||
:
|
||||
<input
|
||||
className="w-4 h-4 cursor-pointer text-primary bg-gray-100 border-gray-300 rounded-sm focus:ring-primary/80 dark:focus:ring-primary dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
|
||||
onChange={(e)=>handleStatusChange(e, item)}
|
||||
type="checkbox"
|
||||
checked={item?.status}
|
||||
name="status"
|
||||
id={'status' + index}
|
||||
/>
|
||||
}
|
||||
</>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-8">
|
||||
<div className="flex justify-center">
|
||||
<>
|
||||
{selected == `signup${index}`
|
||||
?
|
||||
<div role="status" className="text-center">
|
||||
<svg aria-hidden="true" className="w-4 h-4 text-gray-200 animate-spin dark:text-gray-600 fill-primary" viewBox="0 0 100 101" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z" fill="currentColor"/>
|
||||
<path d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z" fill="currentFill"/>
|
||||
</svg>
|
||||
<span className="sr-only">Loading...</span>
|
||||
</div>
|
||||
:
|
||||
<input
|
||||
className="w-4 h-4 cursor-pointer text-primary bg-gray-100 border-gray-300 rounded-sm focus:ring-primary/80 dark:focus:ring-primary dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
|
||||
onChange={(e)=>handleStatusChange(e, item)}
|
||||
type="checkbox"
|
||||
checked={item?.signup}
|
||||
name="signup"
|
||||
id={'signup' + index }
|
||||
/>
|
||||
}
|
||||
</>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
:
|
||||
<tr className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-3 py-2" colSpan={4}>
|
||||
<div className="flex justify-center items-center">
|
||||
No Record Found
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
}
|
||||
</>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -44,9 +44,9 @@ export default function HomeCom() {
|
||||
{/* <p className='text-3xl sm:text-[39px]'><span className='text-xl sm:text-2xl'>{dashData?.loans?.currency_text}</span><CustomCounter targetNumber={dashData?.loans?.value} timeInSeconds='1' /></p> */}
|
||||
<p className='text-xl sm:text-[30px]'><span className='text-lg sm:text-xl'>
|
||||
{/*{dashData?.loans?.currency_text}*/}
|
||||
</span><CustomCounter targetNumber={formatNumber(dashData?.loans?.value)} timeInSeconds='1'/>
|
||||
</span><CustomCounter targetNumber={formatNumber(dashData?.signups?.value)} timeInSeconds='1'/>
|
||||
</p>
|
||||
<p className='sm:text-[13.9px]'>{dashData?.loans?.text}</p>
|
||||
<p className='sm:text-[13.9px]'>{dashData?.signups?.text.toString()}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@@ -104,10 +104,10 @@ export default function HomeCom() {
|
||||
Subscription
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
Status
|
||||
URL
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
Activity
|
||||
Status
|
||||
</th>
|
||||
<th scope="col" className="px-2 text-right">
|
||||
Action
|
||||
@@ -138,24 +138,25 @@ export default function HomeCom() {
|
||||
<div className="text-base font-semibold"><a
|
||||
href={`https://${item?.internal_url}`} target='_blank'
|
||||
rel="noreferrer">{item?.internal_url}</a></div>
|
||||
<div className="font-normal text-gray-500">{item?.status}</div>
|
||||
<div className="font-normal text-gray-500">
|
||||
<a href={`http://${item?.primary_server}:${item?.provision_port}`}
|
||||
target='_blank'
|
||||
rel="noreferrer">
|
||||
{item?.primary_server}:{item?.provision_port} </a></div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="font-normal text-gray-500">50%</div>
|
||||
<div
|
||||
className="relative h-[6px] w-full bg-white-body dark:bg-black-body rounded-full overflow-hidden">
|
||||
<div
|
||||
className={`absolute left-0 h-full w-1/2 bg-emerald-600`}></div>
|
||||
</div>
|
||||
<div className="font-normal text-gray-500">{item?.status}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2 text-right">
|
||||
<div className='flex items-center justify-end gap-3 md:gap-4'>
|
||||
<div
|
||||
className='p-2 flex justify-center items-center text-slate-500 bg-white-body dark:text-white-body dark:bg-black-body rounded-md'>
|
||||
<Link to={`/subscription-view/${item?.uid}`}>
|
||||
<Link to={`/subscription-view/${item?.uid}`}
|
||||
state={{subscriptionUID: item?.uid}}
|
||||
>
|
||||
<Icons name='eye'/>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -157,6 +157,7 @@ const asideNavLinks = [
|
||||
{name: 'Billings', status: 1, icon: 'dot', to: RouteLinks.billings},
|
||||
{
|
||||
name: 'Configurations', status: 1, icon: 'arrow-right', subLinks: [
|
||||
{name: 'Country', status: 1, icon: 'dot', to: RouteLinks.countrySettings},
|
||||
{name: 'Product Settings', status: 1, icon: 'dot', to: RouteLinks.products},
|
||||
{name: 'Product Templates', status: 1, icon: 'dot', to: RouteLinks.productTemplates},
|
||||
{name: 'Custom Templates', status: 1, icon: 'dot', to: RouteLinks.customTemplates},
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||
import {Formik, Form} from 'formik'
|
||||
import * as Yup from "yup";
|
||||
import InputText from '../InputText'
|
||||
import {addCustomTemplate} from '../../services/siteServices'
|
||||
import queryKeys from '../../services/queryKeys';
|
||||
|
||||
|
||||
const initialValues = {
|
||||
custom_id: "",
|
||||
provision_name: "",
|
||||
};
|
||||
|
||||
// To get the validation schema
|
||||
const validationSchema = Yup.object().shape({
|
||||
custom_id: Yup.string().required("custom_id is required").min(6, 'must be upto 6 characters').max(25, 'must not exceed 25 characters'),
|
||||
provision_name: Yup.string().required("provision_name is required").min(6, 'must be upto 6 characters').max(200, 'must not exceed 200 characters'),
|
||||
});
|
||||
|
||||
export default function AddTemplate() {
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const customTemplate = useMutation({
|
||||
mutationFn: (fields) => {
|
||||
if (!fields.custom_id || !fields.provision_name) {
|
||||
throw new Error('Please provide all fields marked *')
|
||||
}
|
||||
return addCustomTemplate(fields)
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.refetchQueries({
|
||||
queryKey: [...queryKeys.custom_template],
|
||||
// type: 'active',
|
||||
// exact: true,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
//FUNCTION TO HANDLE ADD TEMPLATE
|
||||
const handleSubmit = (values, helper) => {
|
||||
customTemplate.mutate(values)
|
||||
};
|
||||
|
||||
return (
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
{(props) => (
|
||||
<Form>
|
||||
<div
|
||||
className='flex flex-col w-full bg-white rounded-xl p-16 sm:px-20 sm:py-16 shadow'>
|
||||
<div className='w-full flex flex-col gap-4'>
|
||||
<div className='relative text-input flex flex-col sm:flex-row gap-2 sm:items-center'>
|
||||
<label className={`text-base min-w-36 text-end sm:text-left ${(props.errors.custom_id && props.touched.custom_id) && 'text-red-500'}`}>
|
||||
Custom ID
|
||||
</label>
|
||||
<InputText
|
||||
id='custom_id'
|
||||
placeholder='Custom ID'
|
||||
name='custom_id'
|
||||
value={props.values.custom_id}
|
||||
handleChange={props.handleChange}
|
||||
/>
|
||||
</div>
|
||||
<div className='relative text-input flex flex-col sm:flex-row gap-2 sm:items-center'>
|
||||
<label className={`text-base min-w-36 text-end sm:text-left ${(props.errors.provision_name && props.touched.provision_name) && 'text-red-500'}`}>
|
||||
Provision Name
|
||||
</label>
|
||||
<InputText
|
||||
id='provision_name'
|
||||
placeholder='Provision Name'
|
||||
name='provision_name'
|
||||
value={props.values.provision_name}
|
||||
handleChange={props.handleChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='h-10 my-5 text-end'>
|
||||
<button type='submit' disabled={customTemplate.isPending}
|
||||
className='px-4 h-full bg-primary text-white font-bold rounded-md'>{customTemplate.isPending ? 'loading...' : 'Add'}</button>
|
||||
</div>
|
||||
|
||||
{customTemplate.error &&
|
||||
<>
|
||||
<div className="w-full text-center">
|
||||
<p className='text-red-500 text-sm'>{customTemplate.error.message}</p>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
{customTemplate.isSuccess &&
|
||||
<>
|
||||
<div className="w-full text-center">
|
||||
<p className='text-emerald-500 text-sm'>{'Template Added'}</p>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
)
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import TablePaginatedWrapper from '../tableWrapper/TablePaginatedWrapper'
|
||||
import Icons from '../Icons'
|
||||
import { getCustomTemplate } from '../../services/siteServices'
|
||||
import getDateTimeFromDateString from '../../helpers/getDateTimeFromDateString'
|
||||
import AddTemplate from './AddTemplate'
|
||||
|
||||
export default function CustomTemplates() {
|
||||
|
||||
@@ -50,7 +51,12 @@ export default function CustomTemplates() {
|
||||
return (
|
||||
<div className='w-full flex flex-col gap-8'>
|
||||
<BreadcrumbCom title='Custom Templates' paths={['Dashboard', 'Custom Templates']} />
|
||||
|
||||
<div className='box bg-white dark:bg-black-box text-black-body dark:text-white-body' style={{backgroundColor: 'aliceblue'}}>
|
||||
<div className='mb-3'>
|
||||
<b>Add New Custom Template</b>
|
||||
</div>
|
||||
<AddTemplate />
|
||||
</div>
|
||||
<div className='box bg-white dark:bg-black-box text-black-body dark:text-white-body'>
|
||||
{ isError ?
|
||||
<p className='text-red-500'>{error?.message}</p>
|
||||
@@ -62,7 +68,8 @@ export default function CustomTemplates() {
|
||||
<div className='w-full sm:max-w-48'>
|
||||
<select name='type' value={filter?.type} className='h-10 w-full p-2 rounded-md' onChange={handleFilter}>
|
||||
<option value=''>All</option>
|
||||
<option value='name'>Name</option>
|
||||
<option value='custom_id'>Custom ID</option>
|
||||
<option value='provision_name'>Provision Name</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className='w-full sm:max-w-48'>
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
import {useMutation, useQueryClient} from '@tanstack/react-query'
|
||||
import {Formik, Form} from 'formik'
|
||||
import * as Yup from "yup";
|
||||
import InputText from '../InputText'
|
||||
import {addCustomTemplate} from '../../services/siteServices'
|
||||
import queryKeys from '../../services/queryKeys';
|
||||
|
||||
|
||||
const initialValues = {
|
||||
custom_id: "",
|
||||
provision_name: "",
|
||||
};
|
||||
|
||||
// To get the validation schema
|
||||
const validationSchema = Yup.object().shape({
|
||||
custom_id: Yup.string().required("custom_id is required").min(6, 'must be upto 6 characters').max(25, 'must not exceed 25 characters'),
|
||||
provision_name: Yup.string().required("provision_name is required").min(6, 'must be upto 6 characters').max(200, 'must not exceed 200 characters'),
|
||||
});
|
||||
|
||||
export default function ProductDetails() {
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const customTemplate = useMutation({
|
||||
mutationFn: (fields) => {
|
||||
if (!fields.custom_id || !fields.provision_name) {
|
||||
throw new Error('Please provide all fields marked *')
|
||||
}
|
||||
return addCustomTemplate(fields)
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.refetchQueries({
|
||||
queryKey: [...queryKeys.custom_template],
|
||||
// type: 'active',
|
||||
// exact: true,
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
//FUNCTION TO HANDLE ADD TEMPLATE
|
||||
const handleSubmit = (values, helper) => {
|
||||
// customTemplate.mutate(values)
|
||||
};
|
||||
|
||||
return (
|
||||
<Formik
|
||||
initialValues={initialValues}
|
||||
validationSchema={validationSchema}
|
||||
onSubmit={handleSubmit}
|
||||
>
|
||||
{(props) => (
|
||||
<Form>
|
||||
<div
|
||||
className='flex flex-col w-full bg-white dark:bg-black-box text-black-body dark:text-white-body rounded-xl p-16 sm:px-20 sm:py-16 shadow'>
|
||||
<div className='w-full flex flex-col gap-4'>
|
||||
<div className='relative text-input flex flex-col sm:flex-row gap-2 sm:items-center'>
|
||||
<label className={`text-base min-w-36 text-end sm:text-left ${(props.errors.custom_id && props.touched.custom_id) && 'text-red-500'}`}>
|
||||
Details
|
||||
</label>
|
||||
<textarea
|
||||
className='p-4 w-full resize-none border outline-none ring-0 dark:bg-transparent dark:border-white-light'
|
||||
rows={4}
|
||||
id='custom_id'
|
||||
placeholder='Enter your description text here ...'
|
||||
name='custom_id'
|
||||
value={props.values.custom_id}
|
||||
handleChange={props.handleChange}
|
||||
/>
|
||||
</div>
|
||||
<div className='relative text-input flex flex-col sm:flex-row gap-2 sm:items-center'>
|
||||
<label className={`text-base min-w-36 text-end sm:text-left ${(props.errors.provision_name && props.touched.provision_name) && 'text-red-500'}`}>
|
||||
Sales Text
|
||||
</label>
|
||||
<textarea
|
||||
className='p-4 w-full resize-none border outline-none ring-0 dark:bg-transparent dark:border-white-light'
|
||||
rows={4}
|
||||
id='provision_name'
|
||||
placeholder='Enter your description text here ...'
|
||||
name='provision_name'
|
||||
value={props.values.provision_name}
|
||||
handleChange={props.handleChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='h-10 my-5 text-end'>
|
||||
<button type='submit' disabled={customTemplate.isPending}
|
||||
className='px-4 h-full bg-primary text-white font-bold rounded-md'>{customTemplate.isPending ? 'loading...' : 'Update'}</button>
|
||||
</div>
|
||||
|
||||
{customTemplate.error &&
|
||||
<>
|
||||
<div className="w-full text-center">
|
||||
<p className='text-red-500 text-sm'>{customTemplate.error.message}</p>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
{customTemplate.isSuccess &&
|
||||
<>
|
||||
<div className="w-full text-center">
|
||||
<p className='text-emerald-500 text-sm'>{'Template Added'}</p>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
)
|
||||
}
|
||||
@@ -81,10 +81,7 @@ export default function ProductTemplates() {
|
||||
<th scope="col" className="px-2 py-2">
|
||||
Product ID
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
Name
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
<th scope="col" className="px-8">
|
||||
Provision Name
|
||||
</th>
|
||||
<th scope="col" className="px-2 text-right">
|
||||
@@ -102,12 +99,7 @@ export default function ProductTemplates() {
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{item?.name}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<td className="px-8">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{item?.provision_name}</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
import {useEffect, useState} from 'react';
|
||||
import {useLocation, useNavigate} from 'react-router-dom'
|
||||
import BreadcrumbCom from '../breadcrumb/BreadcrumbCom'
|
||||
import { useQuery, useQueryClient, useMutation } from '@tanstack/react-query'
|
||||
import queryKeys from '../../services/queryKeys'
|
||||
import { getProductView } from "../../services/siteServices";
|
||||
import ProductDetails from './ProductDetails';
|
||||
|
||||
export default function ProductView() {
|
||||
|
||||
const {state} = useLocation()
|
||||
const navigate = useNavigate()
|
||||
|
||||
useEffect(() => {
|
||||
if (!state?.productID) {
|
||||
navigate(RouteLinks.homePage, {replace: true})
|
||||
}
|
||||
}, [])
|
||||
|
||||
const {data, isFetching, status, isError, error} = useQuery({
|
||||
queryKey: queryKeys.product_view,
|
||||
queryFn: () => {
|
||||
const reqData = {
|
||||
// page,
|
||||
// ...filterData
|
||||
product_id : state?.productID
|
||||
}
|
||||
return getProductView(reqData)
|
||||
},
|
||||
staleTime: 0 // 0 mins
|
||||
})
|
||||
const countryData = data?.data // PRODUCT VIEW LIST
|
||||
console.log('DATA', countryData)
|
||||
|
||||
return (
|
||||
<div className='w-full flex flex-col gap-8'>
|
||||
<BreadcrumbCom title={`Product View [${state?.productID}]`} paths={['Dashboard', 'Product View']}/>
|
||||
|
||||
<div className='flex flex-col gap-4'>
|
||||
<div className='flex flex-col gap-2'>
|
||||
<p className='text-lg dark:text-white-light'>Product Configuration</p>
|
||||
<div className='box bg-white dark:bg-black-box text-black-body dark:text-white-body'>
|
||||
|
||||
<table className="py-2 w-full text-sm">
|
||||
<thead className="py-2 text-sm text-slate-500 text-left">
|
||||
<tr>
|
||||
<th scope="col" className="px-2 py-2" style={{width: '150px'}}>
|
||||
Item
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
Value
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-2 py-2">
|
||||
<div
|
||||
className='w-full min-w-48 flex items-center gap-2 whitespace-nowrap'>
|
||||
<div className="text-left">
|
||||
ProductID
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
P000008
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-2 py-2">
|
||||
<div
|
||||
className='w-full min-w-48 flex items-center gap-2 whitespace-nowrap'>
|
||||
<div className="text-left">
|
||||
ProductID
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
P000008
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-2 py-2">
|
||||
<div
|
||||
className='w-full min-w-48 flex items-center gap-2 whitespace-nowrap'>
|
||||
<div className="text-left">
|
||||
ProductID
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
P000008
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-2 py-2">
|
||||
<div
|
||||
className='w-full min-w-48 flex items-center gap-2 whitespace-nowrap'>
|
||||
<div className="text-left">
|
||||
ProductID
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
P000008
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-2 py-2">
|
||||
<div
|
||||
className='w-full min-w-48 flex items-center gap-2 whitespace-nowrap'>
|
||||
<div className="text-left">
|
||||
ProductID
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
P000008
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-2 py-2">
|
||||
<div
|
||||
className='w-full min-w-48 flex items-center gap-2 whitespace-nowrap'>
|
||||
<div className="text-left">
|
||||
ProductID
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
P000008
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='box bg-[aliceblue] dark:bg-black-box text-black-body dark:text-white-body'>
|
||||
<div className='flex flex-col gap-2'>
|
||||
<p className='text-lg'>Product Details</p>
|
||||
<ProductDetails />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
import { useState } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import {useState} from 'react'
|
||||
import {useQuery} from '@tanstack/react-query'
|
||||
import queryKeys from '../../services/queryKeys'
|
||||
|
||||
import {Link} from 'react-router-dom'
|
||||
import BreadcrumbCom from '../breadcrumb/BreadcrumbCom'
|
||||
import TablePaginatedWrapper from '../tableWrapper/TablePaginatedWrapper'
|
||||
import Icons from '../Icons'
|
||||
import { getProducts } from '../../services/siteServices'
|
||||
import {getProducts} from '../../services/siteServices'
|
||||
import getDateTimeFromDateString from '../../helpers/getDateTimeFromDateString'
|
||||
// import formatNumber from '../../helpers/formatNumber'
|
||||
// import getDateTimeFromDateString from '../../helpers/getDateTimeFromDateString';
|
||||
@@ -19,18 +19,18 @@ export default function ProductsCom() {
|
||||
const [filter, setFilter] = useState({type: '', id: ''})
|
||||
const [willFilter, setWillFilter] = useState(false)
|
||||
|
||||
const handleFilter = ({target:{name, value}}) => {
|
||||
setFilter(prev => ({...prev, [name]:value}))
|
||||
const handleFilter = ({target: {name, value}}) => {
|
||||
setFilter(prev => ({...prev, [name]: value}))
|
||||
}
|
||||
|
||||
const handleFilterByParams = () => {
|
||||
if(filter.type && !filter.id){
|
||||
if (filter.type && !filter.id) {
|
||||
return
|
||||
}else if(!filter.type){
|
||||
} else if (!filter.type) {
|
||||
setPage(1)
|
||||
setWillFilter(prev => !prev)
|
||||
setFilter({type: '', id: ''})
|
||||
}else{
|
||||
} else {
|
||||
setPage(1)
|
||||
setWillFilter(prev => !prev)
|
||||
}
|
||||
@@ -54,91 +54,116 @@ export default function ProductsCom() {
|
||||
|
||||
return (
|
||||
<div className='w-full flex flex-col gap-8'>
|
||||
<BreadcrumbCom title='Products' paths={['Dashboard', 'Products']} />
|
||||
<BreadcrumbCom title='Products' paths={['Dashboard', 'Products']}/>
|
||||
|
||||
<div className='box bg-white dark:bg-black-box text-black-body dark:text-white-body'>
|
||||
{ isError ?
|
||||
{isError ?
|
||||
<p className='text-red-500'>{error?.message}</p>
|
||||
:
|
||||
<>
|
||||
{/* filter section */}
|
||||
<div className='px-2 py-2 mb-4 flex flex-col sm:flex-row flex-wrap sm:items-center gap-2'>
|
||||
<Icons name='filter' className='text-3xl' />
|
||||
<div className='w-full sm:max-w-48'>
|
||||
<select name='type' value={filter?.type} className='h-10 w-full p-2 rounded-md' onChange={handleFilter}>
|
||||
<option value=''>All</option>
|
||||
<option value='name'>Name</option>
|
||||
</select>
|
||||
:
|
||||
<>
|
||||
{/* filter section */}
|
||||
<div className='px-2 py-2 mb-4 flex flex-col sm:flex-row flex-wrap sm:items-center gap-2'>
|
||||
<Icons name='filter' className='text-3xl'/>
|
||||
<div className='w-full sm:max-w-48'>
|
||||
<select name='type' value={filter?.type} className='h-10 w-full p-2 rounded-md'
|
||||
onChange={handleFilter}>
|
||||
<option value=''>All</option>
|
||||
<option value='name'>Name</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className='w-full sm:max-w-48'>
|
||||
<input name='id' value={filter?.id} disabled={!filter.type}
|
||||
className={`h-10 w-full p-2 rounded-md outline-none border border-black-aside ${!filter.type && 'opacity-30'}`}
|
||||
onChange={handleFilter}/>
|
||||
</div>
|
||||
<button onClick={handleFilterByParams} disabled={filter.type && !filter.id}
|
||||
className={`h-10 bg-primary px-2 py-1 rounded-md text-white font-medium sm:self-end ${(filter.type && !filter.id) && 'opacity-50'}`}>Submit
|
||||
</button>
|
||||
</div>
|
||||
<div className='w-full sm:max-w-48'>
|
||||
<input name='id' value={filter?.id} disabled={!filter.type} className={`h-10 w-full p-2 rounded-md outline-none border border-black-aside ${!filter.type && 'opacity-30'}`} onChange={handleFilter} />
|
||||
</div>
|
||||
<button onClick={handleFilterByParams} disabled={filter.type && !filter.id} className={`h-10 bg-primary px-2 py-1 rounded-md text-white font-medium sm:self-end ${(filter.type && !filter.id) && 'opacity-50'}`}>Submit</button>
|
||||
</div>
|
||||
{/* end of filter section */}
|
||||
{/* end of filter section */}
|
||||
|
||||
<TablePaginatedWrapper data={productsData} isFetching={isFetching} setPage={setPage} itemsPerPage={pagination?.limit} pagination={pagination}>
|
||||
{({ data }) => (
|
||||
<>
|
||||
<table className="py-2 w-full text-sm">
|
||||
<thead className="py-2 text-sm text-slate-500 text-left">
|
||||
<tr>
|
||||
<th scope="col" className="px-2 py-2">
|
||||
Added
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
Name
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
Product ID
|
||||
</th>
|
||||
<th scope="col" className="px-2 text-right">
|
||||
Status
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{(data && data.length > 0) ? data?.map((item, index) => (
|
||||
<tr key={index} className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-2 py-2">
|
||||
<div className='w-full min-w-48 flex items-center gap-2 whitespace-nowrap'>
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{getDateTimeFromDateString(item?.added)}</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{item?.name}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{item?.product_id}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-right">
|
||||
<div className="text-base font-semibold">{item?.status}</div>
|
||||
</div>
|
||||
</td>
|
||||
<TablePaginatedWrapper data={productsData} isFetching={isFetching} setPage={setPage}
|
||||
itemsPerPage={pagination?.limit} pagination={pagination}>
|
||||
{({data}) => (
|
||||
<>
|
||||
<table className="py-2 w-full text-sm">
|
||||
<thead className="py-2 text-sm text-slate-500 text-left">
|
||||
<tr>
|
||||
<th scope="col" className="px-2 py-2">
|
||||
Added
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
Name
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
Product ID
|
||||
</th>
|
||||
<th scope="col" className="px-2 text-right">
|
||||
Status
|
||||
</th>
|
||||
<th scope="col" className="px-2 text-right">
|
||||
Action
|
||||
</th>
|
||||
</tr>
|
||||
))
|
||||
:
|
||||
<tr className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-3 py-2" colSpan={4}>
|
||||
<div className="flex justify-center items-center">
|
||||
No Record Found
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
)}
|
||||
</TablePaginatedWrapper>
|
||||
</>
|
||||
</thead>
|
||||
<tbody>
|
||||
{(data && data.length > 0) ? data?.map((item, index) => (
|
||||
<tr key={index} className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-2 py-2">
|
||||
<div
|
||||
className='w-full min-w-48 flex items-center gap-2 whitespace-nowrap'>
|
||||
<div className="text-left">
|
||||
<div
|
||||
className="text-base font-semibold">{getDateTimeFromDateString(item?.added)}</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{item?.name}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div
|
||||
className="text-base font-semibold">{item?.product_id}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-right">
|
||||
<div className="text-base font-semibold">{item?.status}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
|
||||
<div
|
||||
className='p-2 flex justify-center items-center text-slate-500 bg-white-body dark:text-white-body dark:bg-black-body rounded-md'>
|
||||
<Link to={`/product-view/${item?.product_id}`} state={{productID: item?.product_id}}>
|
||||
<Icons name='eye'/>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/*<div className="text-right">*/}
|
||||
{/* <div className="text-base font-semibold">[---]</div>*/}
|
||||
{/*</div>*/}
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
:
|
||||
<tr className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-3 py-2" colSpan={4}>
|
||||
<div className="flex justify-center items-center">
|
||||
No Record Found
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
)}
|
||||
</TablePaginatedWrapper>
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,32 +1,201 @@
|
||||
import {useLocation, useNavigate, Link} from 'react-router-dom'
|
||||
import { useQuery, useMutation } from '@tanstack/react-query'
|
||||
import { FaCaretDown } from "react-icons/fa";
|
||||
import BreadcrumbCom from '../breadcrumb/BreadcrumbCom'
|
||||
import { useEffect } from 'react';
|
||||
import {useEffect, useState} from 'react';
|
||||
import RouteLinks from '../../RouteLinks';
|
||||
import { getSubscriptionsView, updateTemplate, updateCustomTemplate } from '../../services/siteServices'
|
||||
import queryKeys from '../../services/queryKeys'
|
||||
import getDateTimeFromDateString from '../../helpers/getDateTimeFromDateString';
|
||||
|
||||
export default function SubscriptionViewCom() {
|
||||
|
||||
const subscriptionUID = "63554d40-9ba1-4afe-80c2-ca147236f7ee";
|
||||
|
||||
const {state:{memberUID}} = useLocation()
|
||||
const {state} = useLocation()
|
||||
const navigate = useNavigate()
|
||||
|
||||
useEffect(()=>{
|
||||
if(!memberUID){
|
||||
navigate(`/account-view/${memberUID}`, {replace: true, state:{memberUID}})
|
||||
const [reqStatus, setReqStatus] = useState({loading: false, type: '', error: false, success: false})
|
||||
|
||||
const [values, setValues] = useState({custom_id: '', template_uid: ''})
|
||||
|
||||
const handleValueChange = ({target:{name, value}}) => {
|
||||
if(name == 'custom_template'){
|
||||
setValues(prev => ({...prev, custom_id: value}))
|
||||
}else if (name == 'template') {
|
||||
setValues(prev => ({...prev, template_uid: value}))
|
||||
}else{
|
||||
setValues(prev => ({...prev}))
|
||||
}
|
||||
},[])
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!state?.subscriptionUID) {
|
||||
navigate(RouteLinks.homePage, {replace: true})
|
||||
}
|
||||
}, [])
|
||||
|
||||
const {data, isFetching, isError, error} = useQuery({
|
||||
queryKey: queryKeys.subscriptions_view,
|
||||
queryFn: () => {
|
||||
// const filterData = filter?.type ? {[filter?.type]: filter.id} : {}
|
||||
const reqData = {
|
||||
subscription_uid: state?.subscriptionUID
|
||||
// page,
|
||||
// ...filterData
|
||||
}
|
||||
return getSubscriptionsView(reqData)
|
||||
},
|
||||
staleTime: 0 //0 mins
|
||||
})
|
||||
const subscriptionViewData = data?.data // ACCOUNT VIEW DATA
|
||||
const customTemplates = subscriptionViewData?.available_custom_templates
|
||||
const availableTemplates = subscriptionViewData?.available_templates
|
||||
const selectedSubscription = subscriptionViewData?.subscription
|
||||
const currentCustomTem = subscriptionViewData?.available_custom_templates?.filter(item => item?.custom_id == subscriptionViewData?.subscription?.custom_template)[0]?.custom_id
|
||||
const currentTemplate = subscriptionViewData?.available_templates?.filter(item => item?.template_uid == subscriptionViewData?.subscription?.product_template)[0]?.template_uid
|
||||
// // console.log('subscriptionViewData', subscriptionViewData, currentCustomTem, currentTemplate)
|
||||
|
||||
// useEffect(()=>{
|
||||
// if(data){
|
||||
// const currentCustomTem = subscriptionViewData?.available_custom_templates?.filter(item => item?.custom_id == subscriptionViewData?.subscription?.custom_template)[0]?.custom_id
|
||||
// const currentTemplate = subscriptionViewData?.available_templates?.filter(item => item?.template_uid == subscriptionViewData?.subscription?.product_template)[0]?.template_uid
|
||||
// setValues({custom_id: currentCustomTem || '', template_uid: currentTemplate || ''})
|
||||
// }
|
||||
// },[data])
|
||||
|
||||
|
||||
const templateUpdate = useMutation({
|
||||
mutationFn: (fields) => {
|
||||
return updateTemplate(fields)
|
||||
},
|
||||
// onError: (error) => {
|
||||
// },
|
||||
// onSuccess: (res) => {
|
||||
// },
|
||||
onSettled: () => {
|
||||
setTimeout(()=>{
|
||||
templateUpdate.reset()
|
||||
}, 3000)
|
||||
}
|
||||
})
|
||||
|
||||
const customTemplateUpdate = useMutation({
|
||||
mutationFn: (fields) => {
|
||||
return updateCustomTemplate(fields)
|
||||
},
|
||||
// onError: (error) => {
|
||||
// },
|
||||
// onSuccess: (res) => {
|
||||
// },
|
||||
onSettled: () => {
|
||||
setTimeout(()=>{
|
||||
customTemplateUpdate.reset()
|
||||
}, 3000)
|
||||
}
|
||||
})
|
||||
|
||||
const handleUpdateTemplate = () => {
|
||||
const reqData = {
|
||||
subscrtiption_uid: state?.subscriptionUID,
|
||||
template_uid: values.template_uid
|
||||
}
|
||||
templateUpdate.mutate(reqData)
|
||||
}
|
||||
|
||||
const handleUpdateCustomTemplate = () => {
|
||||
const reqData = {
|
||||
subscrtiption_uid: state?.subscriptionUID,
|
||||
custom_id: values.custom_id
|
||||
}
|
||||
customTemplateUpdate.mutate(reqData)
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<div className='w-full flex flex-col gap-8'>
|
||||
<BreadcrumbCom title={`Subscription View [${memberUID}]`} paths={['Dashboard', 'Subscription View']}/>
|
||||
<BreadcrumbCom title={`Subscription View [${state?.subscriptionUID}]`} paths={['Dashboard', 'Subscription View']}/>
|
||||
|
||||
<div className='box bg-white dark:bg-black-box text-black-body dark:text-white-body'>
|
||||
{isFetching ?
|
||||
<>
|
||||
<p className='text-slate-800'>Loading...</p>
|
||||
</>
|
||||
: isError ?
|
||||
<p className='text-red-500'>{error.message}</p>
|
||||
:
|
||||
<>
|
||||
<div className='w-full box bg-white dark:bg-black-box text-black-body dark:text-white-body overflow-x-auto'>
|
||||
<table className="py-2 w-full text-sm bg-[aliceblue] dark:bg-transparent rounded-[10px]">
|
||||
<tbody>
|
||||
<tr className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-2 py-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{getDateTimeFromDateString(selectedSubscription?.added)}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{selectedSubscription?.product_id}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{selectedSubscription?.internal_url}
|
||||
<br /><span>Template :</span> {selectedSubscription?.product_template}
|
||||
<br /><span>Custom :</span> {selectedSubscription?.custom_template}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-right">
|
||||
<div className="text-base font-semibold">{selectedSubscription?.status}</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<>
|
||||
Show all here
|
||||
</>
|
||||
<div className='box bg-white dark:bg-black-box text-black-body dark:text-white-body'>
|
||||
|
||||
<div className='w-full'>
|
||||
<label className='font-medium'>Assign Template</label>
|
||||
<div className='flex flex-col xs:flex-row md:items-center gap-2'>
|
||||
<div className='w-full h-10 relative overflow-hidden rounded-md'>
|
||||
<select name='template' value={currentTemplate || values.template_uid} onChange={handleValueChange} className='w-full h-full p-2 appearance-none dark:bg-transparent border-0 dark:border-1 border-white ring-0 outline-none'>
|
||||
<option value=''>None</option>
|
||||
{availableTemplates && availableTemplates.map(item => (
|
||||
<option key={item?.template_uid} value={item?.template_uid}>{`${item?.product_id}-${item?.provision_name}`}</option>
|
||||
))}
|
||||
</select>
|
||||
<FaCaretDown className='text-base absolute top-1/2 -translate-y-1/2 right-2' />
|
||||
</div>
|
||||
<button name='template' onClick={handleUpdateTemplate} disabled={(templateUpdate.isPending || !values.template_uid)} className={`rounded-md p-2 bg-primary text-white text-center ${(templateUpdate.isPending || !values.template_uid) && 'opacity-50'}`}>Update</button>
|
||||
</div>
|
||||
<p className={`p-2 mt-4 ${templateUpdate.isSuccess ? 'text-emerald-500' : 'text-red-500'}`}>{templateUpdate.isSuccess ? 'Template updated' : templateUpdate.isSuccess ? 'Unable to complete request, try again' : ''}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div className='box bg-white dark:bg-black-box text-black-body dark:text-white-body'>
|
||||
|
||||
<div className='w-full'>
|
||||
<label className='font-medium'>Assign Custom Template</label>
|
||||
<div className='flex flex-col xs:flex-row md:items-center gap-2'>
|
||||
<div className='w-full h-10 relative overflow-hidden rounded-md'>
|
||||
<select name='custom_template' value={currentCustomTem || values.custom_id} onChange={handleValueChange} className='w-full h-full p-2 appearance-none dark:bg-transparent border-0 dark:border-1 border-white ring-0 outline-none'>
|
||||
<option value=''>None</option>
|
||||
{customTemplates && customTemplates.map(item => (
|
||||
<option key={item?.custom_id} value={item?.custom_id}>{`${item?.custom_id}-${item?.provision_name}`}</option>
|
||||
))}
|
||||
</select>
|
||||
<FaCaretDown className='text-base absolute top-1/2 -translate-y-1/2 right-2' />
|
||||
</div>
|
||||
<button name='custom_template' onClick={handleUpdateCustomTemplate} disabled={(customTemplateUpdate.isPending || !values.custom_id)} className={`rounded-md p-2 bg-primary text-white text-center ${(customTemplateUpdate.isPending || !values.custom_id) && 'opacity-50'}`}>Update</button>
|
||||
</div>
|
||||
<p className={`p-2 mt-4 ${customTemplateUpdate.isSuccess ? 'text-emerald-500' : 'text-red-500'}`}>{customTemplateUpdate.isSuccess ? 'Custom Template updated' : customTemplateUpdate.isSuccess ? 'Unable to complete request, try again' : ''}</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,14 +1,14 @@
|
||||
import { useState } from 'react'
|
||||
import {useState} from 'react'
|
||||
import {Link} from 'react-router-dom'
|
||||
|
||||
// import {Link} from 'react-router-dom'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import {useQuery} from '@tanstack/react-query'
|
||||
import queryKeys from '../../services/queryKeys'
|
||||
|
||||
import BreadcrumbCom from '../breadcrumb/BreadcrumbCom'
|
||||
import TablePaginatedWrapper from '../tableWrapper/TablePaginatedWrapper'
|
||||
import Icons from '../Icons'
|
||||
import { getSubscriptions } from '../../services/siteServices'
|
||||
import {getSubscriptions} from '../../services/siteServices'
|
||||
import getDateTimeFromDateString from '../../helpers/getDateTimeFromDateString';
|
||||
// import localImgLoader from '../../helpers/localImageLoader';
|
||||
// import RouteLinks from '../../RouteLinks';
|
||||
@@ -19,18 +19,18 @@ export default function SubscriptionsCom() {
|
||||
const [filter, setFilter] = useState({type: '', id: ''})
|
||||
const [willFilter, setWillFilter] = useState(false)
|
||||
|
||||
const handleFilter = ({target:{name, value}}) => {
|
||||
setFilter(prev => ({...prev, [name]:value}))
|
||||
const handleFilter = ({target: {name, value}}) => {
|
||||
setFilter(prev => ({...prev, [name]: value}))
|
||||
}
|
||||
|
||||
const handleFilterByParams = () => {
|
||||
if(filter.type && !filter.id){
|
||||
if (filter.type && !filter.id) {
|
||||
return
|
||||
}else if(!filter.type){
|
||||
} else if (!filter.type) {
|
||||
setPage(1)
|
||||
setWillFilter(prev => !prev)
|
||||
setFilter({type: '', id: ''})
|
||||
}else{
|
||||
} else {
|
||||
setPage(1)
|
||||
setWillFilter(prev => !prev)
|
||||
}
|
||||
@@ -53,108 +53,138 @@ export default function SubscriptionsCom() {
|
||||
|
||||
return (
|
||||
<div className='w-full flex flex-col gap-8'>
|
||||
<BreadcrumbCom title='Provisions' paths={['Dashboard', 'Provisions']} />
|
||||
<BreadcrumbCom title='Provisions' paths={['Dashboard', 'Provisions']}/>
|
||||
|
||||
<div className='box bg-white dark:bg-black-box text-black-body dark:text-white-body'>
|
||||
{ isError ?
|
||||
{isError ?
|
||||
<p className='text-red-500'>{error?.message}</p>
|
||||
:
|
||||
<>
|
||||
{/* filter section */}
|
||||
<div className='px-2 py-2 mb-4 flex flex-col sm:flex-row flex-wrap sm:items-center gap-2'>
|
||||
<Icons name='filter' className='text-3xl' />
|
||||
<div className='w-full sm:max-w-48'>
|
||||
<select name='type' value={filter?.type} className='h-10 w-full p-2 rounded-md' onChange={handleFilter}>
|
||||
<option value=''>All</option>
|
||||
<option value='member_id'>Member ID</option>
|
||||
<option value='product_id'>Product ID</option>
|
||||
</select>
|
||||
:
|
||||
<>
|
||||
{/* filter section */}
|
||||
<div className='px-2 py-2 mb-4 flex flex-col sm:flex-row flex-wrap sm:items-center gap-2'>
|
||||
<Icons name='filter' className='text-3xl'/>
|
||||
<div className='w-full sm:max-w-48'>
|
||||
<select name='type' value={filter?.type} className='h-10 w-full p-2 rounded-md'
|
||||
onChange={handleFilter}>
|
||||
<option value=''>All</option>
|
||||
<option value='member_id'>Member ID</option>
|
||||
<option value='product_id'>Product ID</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className='w-full sm:max-w-48'>
|
||||
<input name='id' value={filter?.id} disabled={!filter.type}
|
||||
className={`h-10 w-full p-2 rounded-md outline-none border border-black-aside ${!filter.type && 'opacity-30'}`}
|
||||
onChange={handleFilter}/>
|
||||
</div>
|
||||
<button onClick={handleFilterByParams} disabled={filter.type && !filter.id}
|
||||
className={`h-10 bg-primary px-2 py-1 rounded-md text-white font-medium sm:self-end ${(filter.type && !filter.id) && 'opacity-50'}`}>Submit
|
||||
</button>
|
||||
</div>
|
||||
<div className='w-full sm:max-w-48'>
|
||||
<input name='id' value={filter?.id} disabled={!filter.type} className={`h-10 w-full p-2 rounded-md outline-none border border-black-aside ${!filter.type && 'opacity-30'}`} onChange={handleFilter} />
|
||||
</div>
|
||||
<button onClick={handleFilterByParams} disabled={filter.type && !filter.id} className={`h-10 bg-primary px-2 py-1 rounded-md text-white font-medium sm:self-end ${(filter.type && !filter.id) && 'opacity-50'}`}>Submit</button>
|
||||
</div>
|
||||
{/* end of filter section */}
|
||||
{/* end of filter section */}
|
||||
|
||||
<TablePaginatedWrapper data={subscriptionData} isFetching={isFetching} setPage={setPage} itemsPerPage={pagination?.limit} pagination={pagination}>
|
||||
{({ data }) => (
|
||||
<>
|
||||
<table className="py-2 w-full text-sm">
|
||||
<thead className="py-2 text-sm text-slate-500 text-left">
|
||||
<tr>
|
||||
<th scope="col" className="px-2 py-2">
|
||||
Added
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
Product
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
URL
|
||||
</th>
|
||||
<th scope="col" className="px-2 text-right">
|
||||
Status
|
||||
</th>
|
||||
<th scope="col" className="px-2 text-right">
|
||||
Action
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{(data && data.length > 0) ? data?.map((item, index) => (
|
||||
<tr key={index} className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-2 py-2">
|
||||
<div className='w-full min-w-48 flex items-center gap-2 whitespace-nowrap'>
|
||||
{/* <img className="w-10 h-10 rounded-md" src={localImgLoader(`loan_icons/${item?.type}.png`)} alt="Icon" /> */}
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{getDateTimeFromDateString(item?.added)}</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{item?.product_id}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base font-semibold">{item?.internal_url}</div>
|
||||
<div className="font-normal text-gray-500">{item?.external_url}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-right">
|
||||
<div className="text-base font-semibold">{item?.status}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2 text-right">
|
||||
<div className='flex items-center justify-end gap-3 md:gap-4'>
|
||||
<div
|
||||
className='p-2 flex justify-center items-center text-slate-500 bg-white-body dark:text-white-body dark:bg-black-body rounded-md'>
|
||||
<Link to={`/subscription-view/${item?.subscription_uid}`}
|
||||
state={{customerID: item?.id, memberUID: item?.member_uid}}>
|
||||
<Icons name='eye'/>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<TablePaginatedWrapper data={subscriptionData} isFetching={isFetching} setPage={setPage}
|
||||
itemsPerPage={pagination?.limit} pagination={pagination}>
|
||||
{({data}) => (
|
||||
<>
|
||||
<table className="py-2 w-full text-sm">
|
||||
<thead className="py-2 text-sm text-slate-500 text-left">
|
||||
<tr>
|
||||
<th scope="col" className="px-2 py-2">
|
||||
Added/Updated
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
Product/Server
|
||||
</th>
|
||||
<th scope="col" className="px-2">
|
||||
Internal-URL/External-URL/SubscriptionUID
|
||||
</th>
|
||||
<th scope="col" className="px-2 text-right">
|
||||
Status
|
||||
</th>
|
||||
<th scope="col" className="px-2 text-right">
|
||||
Action
|
||||
</th>
|
||||
</tr>
|
||||
))
|
||||
:
|
||||
<tr className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-3 py-2" colSpan={4}>
|
||||
<div className="flex justify-center items-center">
|
||||
No Record Found
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
)}
|
||||
</TablePaginatedWrapper>
|
||||
</>
|
||||
</thead>
|
||||
<tbody>
|
||||
{(data && data.length > 0) ? data?.map((item, index) => (
|
||||
<tr key={index} className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-2 py-2">
|
||||
<div
|
||||
className='w-full min-w-48 flex items-center gap-2 whitespace-nowrap'>
|
||||
{/* <img className="w-10 h-10 rounded-md" src={localImgLoader(`loan_icons/${item?.type}.png`)} alt="Icon" /> */}
|
||||
<div className="text-left">
|
||||
<div
|
||||
className="text-base font-semibold">
|
||||
{getDateTimeFromDateString(item?.added)}<br/>
|
||||
{getDateTimeFromDateString(item?.updated)}<br/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div
|
||||
className="text-base font-semibold">
|
||||
{item?.product_id}
|
||||
<br/>
|
||||
<a href={`http://${item?.primary_server}:${item?.provision_port}`}
|
||||
target='_blank'
|
||||
rel="noreferrer">{item?.primary_server}:{item?.provision_port}</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-left">
|
||||
<div className="text-base">
|
||||
<span>Int :</span><a href={`https://${item?.internal_url}`}
|
||||
target='_blank'
|
||||
rel="noreferrer"> {item?.internal_url}</a>
|
||||
<br/>
|
||||
<span>Ext :</span><a href={`https://${item?.external_url}`}
|
||||
target='_blank'
|
||||
rel="noreferrer"> {item?.external_url}</a>
|
||||
<br/>
|
||||
{item?.subscription_uid}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2">
|
||||
<div className="text-right">
|
||||
<div className="text-base font-semibold">{item?.status}</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="px-2 text-right">
|
||||
<div className='flex items-center justify-end gap-3 md:gap-4'>
|
||||
<div
|
||||
className='p-2 flex justify-center items-center text-slate-500 bg-white-body dark:text-white-body dark:bg-black-body rounded-md'>
|
||||
<Link to={`/subscription-view/${item?.subscription_uid}`}
|
||||
state={{
|
||||
customerID: item?.id,
|
||||
subscriptionUID: item?.subscription_uid
|
||||
}}
|
||||
>
|
||||
<Icons name='eye'/>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
:
|
||||
<tr className="py-2 border-t border-dashed border-slate-300">
|
||||
<td className="px-3 py-2" colSpan={4}>
|
||||
<div className="flex justify-center items-center">
|
||||
No Record Found
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
)}
|
||||
</TablePaginatedWrapper>
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import React from 'react'
|
||||
import CountrySettings from "../components/country/CountrySettings";
|
||||
|
||||
export default function CountrySettingsPage() {
|
||||
return (
|
||||
<CountrySettings />
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import React from 'react'
|
||||
import ProductView from "../components/products/ProductView";
|
||||
|
||||
export default function ProductViewPage() {
|
||||
return (
|
||||
<ProductView />
|
||||
)
|
||||
}
|
||||
@@ -20,7 +20,10 @@ const queryKeys = {
|
||||
products_template: ['products_template'],
|
||||
custom_template: ['custom_template'],
|
||||
account_view: ['account_view'],
|
||||
subscriptions_view: ['subscriptions_view'],
|
||||
users_admin: ['users_admin'],
|
||||
country_list: ['country_list'],
|
||||
product_view: ['product_view'],
|
||||
}
|
||||
|
||||
export default queryKeys
|
||||
@@ -62,6 +62,26 @@ export const getCustomers = (reqData) => {
|
||||
return getAuxEnd(`/customers`, postData)
|
||||
}
|
||||
|
||||
// FUNCTION TO GET COUNTRY
|
||||
export const getCountry = (reqData) => {
|
||||
const postData = { ...reqData }
|
||||
return getAuxEnd(`/country`, postData)
|
||||
}
|
||||
|
||||
// FUNCTION TO GET PRODUCT VIEW lIST
|
||||
export const getProductView = (reqData) => {
|
||||
const postData = { ...reqData }
|
||||
return getAuxEnd(`/product-view`, postData)
|
||||
}
|
||||
|
||||
// FUNCTION TO SET COUNTRY
|
||||
export const setCountry = (reqData) => {
|
||||
let postData = {
|
||||
...reqData
|
||||
}
|
||||
return postAuxEnd('/set-country', postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO GET BILLINGS
|
||||
export const getBillings = (reqData) => {
|
||||
const postData = { ...reqData }
|
||||
@@ -104,6 +124,30 @@ export const getProductsTemplate = (reqData) => {
|
||||
return getAuxEnd(`/products-templates`, postData)
|
||||
}
|
||||
|
||||
// FUNCTION TO UPDATE TEMPLATE
|
||||
export const updateTemplate = (reqData) => {
|
||||
let postData = {
|
||||
...reqData
|
||||
}
|
||||
return postAuxEnd('/template/set-template', postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO UPDATE CUSTOM TEMPLATE
|
||||
export const updateCustomTemplate = (reqData) => {
|
||||
let postData = {
|
||||
...reqData
|
||||
}
|
||||
return postAuxEnd('/template/set-custom', postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO ADD CUSTOM TEMPLATE
|
||||
export const addCustomTemplate = (reqData) => {
|
||||
let postData = {
|
||||
...reqData
|
||||
}
|
||||
return postAuxEnd('/template/custom-add', postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO GET CUSTOM TEMPLATE DATA
|
||||
export const getCustomTemplate = (reqData) => {
|
||||
const postData = { ...reqData }
|
||||
@@ -116,6 +160,12 @@ export const getAccountView = (reqData) => {
|
||||
return getAuxEnd(`/account-view`, postData)
|
||||
}
|
||||
|
||||
// FUNCTION TO GET SUBSCRIPTIONS VIEW DATA
|
||||
export const getSubscriptionsView = (reqData) => {
|
||||
const postData = { ...reqData }
|
||||
return getAuxEnd(`/subscription-view`, postData)
|
||||
}
|
||||
|
||||
|
||||
// FUNCTION TO GET LOANS TABLE
|
||||
export const getLoans = (reqData) => {
|
||||
|
||||
Reference in New Issue
Block a user