Compare commits

..

22 Commits

Author SHA1 Message Date
victorAnumudu b142833901 set country endpoint added 2025-10-07 08:46:52 +01:00
victorAnumudu 50551f1c7d Checkbox added 2025-10-06 21:21:05 +01:00
ameye a87a0a58db Merge branch 'country-endpoint-fix' of MERMS/MermsFirstOffice into master 2025-10-06 19:25:22 +00:00
victorAnumudu 6927d53c59 fixed endpoint 2025-10-06 20:01:48 +01:00
ameye e24df8e744 Merge branch 'country-endpoint' of MERMS/MermsFirstOffice into master 2025-10-06 17:43:23 +00:00
victorAnumudu 20c224b625 added country endpoint 2025-10-06 17:50:38 +01:00
CHIEFSOFT\ameye 54a0361620 country page 2025-10-06 06:07:21 -04:00
CHIEFSOFT\ameye a9721991de Added links 2025-10-06 05:05:14 -04:00
CHIEFSOFT\ameye e15e9f271c Fid URL 2025-10-01 05:46:45 -04:00
CHIEFSOFT\ameye c9ad818370 added urls 2025-10-01 04:42:10 -04:00
CHIEFSOFT\ameye 466d10c0fc added ips 2025-09-30 18:28:42 -04:00
ameye 7a7149de0c Merge branch 'payload-fix' of MERMS/MermsFirstOffice into master 2025-09-30 17:54:11 +00:00
victorAnumudu 34ef37c905 fixed payload issue 2025-09-30 18:38:53 +01:00
ameye 52249ae3a2 Merge branch 'update-custom-template-fix' of MERMS/MermsFirstOffice into master 2025-09-30 17:01:32 +00:00
victorAnumudu 183a6ce903 fixed custom update endpoint 2025-09-30 17:49:42 +01:00
ameye e65371e41b Merge branch 'template-current-selection' of MERMS/MermsFirstOffice into master 2025-09-30 08:50:08 +00:00
victorAnumudu 767a900e36 fixed default template selection 2025-09-30 08:31:37 +01:00
CHIEFSOFT\ameye 8f41dcbf35 fix endpoinst 2025-09-29 20:36:24 -04:00
ameye 11289c44fb Merge branch 'subscription-view-component' of MERMS/MermsFirstOffice into master 2025-09-29 21:07:36 +00:00
victorAnumudu 65f4aafc68 add template layout fix 2025-09-29 22:04:52 +01:00
victorAnumudu 79d5005d6b added custom template and template dropdown menu 2025-09-29 21:46:23 +01:00
ameye ba6b3a1dd0 Merge branch 'link-error-fixed' of MERMS/MermsFirstOffice into master 2025-09-29 17:39:35 +00:00
14 changed files with 541 additions and 66 deletions
+1
View File
@@ -9,6 +9,7 @@ const RouteLinks = {
recentSignup: '/recent-signup',
loansPage: '/loans',
transactionsPage: '/transactions',
countrySettings: '/country',
products: '/products',
usersAdmin: '/users-admin',
productTemplates: '/products-template',
+3 -1
View File
@@ -20,7 +20,8 @@ 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"; // TRANSACTION DETAILS PAGE
// const Home = lazy(() => import('./pages/Home'));
@@ -40,6 +41,7 @@ export default function SiteRoutes() {
<Route path={RouteLinks.products} element={<ProductsPage/>}/> {`*/PRODUCTS 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*/`}
@@ -19,13 +19,13 @@ export default function CustomerSubscriptionsView({subscriptions}) {
#
</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 / Templates
URL / EXT/ Templates
</th>
<th scope="col" className="px-2">
Status
@@ -40,24 +40,45 @@ export default function CustomerSubscriptionsView({subscriptions}) {
<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}
<br /><span>Template :</span> {item?.product_template}
<br /><span>Custom :</span> {item?.custom_template}
<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>
@@ -70,7 +91,10 @@ export default function CustomerSubscriptionsView({subscriptions}) {
<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}}>
<Link to={`/subscription-view/${item?.subscription_uid}`} state={{
customerID: item?.id,
subscriptionUID: item?.subscription_uid
}}>
<Icons name='eye'/>
</Link>
</div>
+182
View File
@@ -0,0 +1,182 @@
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
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.toLowerCase() == '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' ?
<p className='text-slate-800'>Loading...</p>
: isError ?
<p className='text-red-500'>{error.message}</p>
:
<TableWrapper data={countryData} itemsPerPage={20}>
{({ 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">
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>
{(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="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" class="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 class="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" class="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 class="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>
</>
)}
</TableWrapper>
}
{/* {(isFetching && status != 'pending') &&
<div className="w-full absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 z-[991] inset-0 flex justify-center items-center">
<p className="rounded-md shadow-md p-4 bg-white/90 dark:bg-gray-900 text-brown dark:text-white">Loading...</p>
</div>
} */}
</>
</div>
</div>
);
}
+11 -12
View File
@@ -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,17 +138,16 @@ 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">
@@ -156,7 +155,7 @@ export default function HomeCom() {
<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}`}
state={{subscriptionUID: item?.uid}}
state={{subscriptionUID: item?.uid}}
>
<Icons name='eye'/>
</Link>
@@ -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},
+106
View File
@@ -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>
)
}
+5 -3
View File
@@ -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() {
@@ -51,9 +52,10 @@ export default function CustomTemplates() {
<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'}}>
<b>Add New Custom Template</b>
<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 ?
+2 -10
View File
@@ -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>
@@ -1,11 +1,12 @@
import {useLocation, useNavigate, Link} from 'react-router-dom'
import { useQuery } from '@tanstack/react-query'
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 } from '../../services/siteServices'
import { getSubscriptionsView, updateTemplate, updateCustomTemplate } from '../../services/siteServices'
import queryKeys from '../../services/queryKeys'
import getDateTimeFromDateString from '../../helpers/getDateTimeFromDateString';
export default function SubscriptionViewCom() {
@@ -13,6 +14,20 @@ export default function SubscriptionViewCom() {
const {state} = useLocation()
const navigate = useNavigate()
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})
@@ -33,7 +48,68 @@ export default function SubscriptionViewCom() {
staleTime: 0 //0 mins
})
const subscriptionViewData = data?.data // ACCOUNT VIEW DATA
console.log('subscriptionViewData', subscriptionViewData)
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'>
@@ -47,28 +123,55 @@ export default function SubscriptionViewCom() {
<p className='text-red-500'>{error.message}</p>
:
<>
<div className='box bg-white dark:bg-black-box text-black-body dark:text-white-body'>
<div>
Repeat the Subscription at the top
</div>
<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>
<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 md:flex-row md:items-center gap-2'>
<div className='w-full relative'>
<select className='w-full p-2'>
<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>Update</button>
<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>
@@ -76,22 +179,23 @@ export default function SubscriptionViewCom() {
<div className='w-full'>
<label className='font-medium'>Assign Custom Template</label>
<div className='flex flex-col md:flex-row md:items-center gap-2'>
<div className='w-full relative'>
<select className='w-full p-2'>
<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>Update</button>
<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>
)
}
@@ -93,7 +93,7 @@ export default function SubscriptionsCom() {
Added/Updated
</th>
<th scope="col" className="px-2">
Product
Product/Server
</th>
<th scope="col" className="px-2">
Internal-URL/External-URL/SubscriptionUID
@@ -116,8 +116,8 @@ export default function SubscriptionsCom() {
<div className="text-left">
<div
className="text-base font-semibold">
{getDateTimeFromDateString(item?.added)}<br />
{getDateTimeFromDateString(item?.updated)}<br />
{getDateTimeFromDateString(item?.added)}<br/>
{getDateTimeFromDateString(item?.updated)}<br/>
</div>
</div>
</div>
@@ -125,14 +125,26 @@ export default function SubscriptionsCom() {
<td className="px-2">
<div className="text-left">
<div
className="text-base font-semibold">{item?.product_id}</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 font-semibold ">
<span>Int :</span> {item?.internal_url}<br/>
<span>Ext :</span> {item?.external_url}<br/>
<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>
@@ -146,7 +158,10 @@ export default function SubscriptionsCom() {
<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}}
state={{
customerID: item?.id,
subscriptionUID: item?.subscription_uid
}}
>
<Icons name='eye'/>
</Link>
+8
View File
@@ -0,0 +1,8 @@
import React from 'react'
import CountrySettings from "../components/country/CountrySettings";
export default function CountrySettingsPage() {
return (
<CountrySettings />
)
}
+1
View File
@@ -22,6 +22,7 @@ const queryKeys = {
account_view: ['account_view'],
subscriptions_view: ['subscriptions_view'],
users_admin: ['users_admin'],
country_list: ['country_list'],
}
export default queryKeys
+39 -1
View File
@@ -62,6 +62,20 @@ 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 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 +118,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 }
@@ -119,7 +157,7 @@ export const getAccountView = (reqData) => {
// FUNCTION TO GET SUBSCRIPTIONS VIEW DATA
export const getSubscriptionsView = (reqData) => {
const postData = { ...reqData }
return getAuxEnd(`/subcription-view`, postData)
return getAuxEnd(`/subscription-view`, postData)
}