Compare commits
41 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 66a2bcacd5 | |||
| ec9d84b779 | |||
| 8ee793d11e | |||
| 46f17cbdfe | |||
| 283994e43a | |||
| b7d242ff0a | |||
| f6bae30bdd | |||
| a7e2e865de | |||
| 51887cf0d6 | |||
| 5ea1047356 | |||
| 9b9a7cc5da | |||
| 290e1fbd7e | |||
| 6884aa19b2 | |||
| 597a45dcba | |||
| 4f7274c30c | |||
| 290356780c | |||
| bd1450887b | |||
| 923a2483ed | |||
| 7f0ccf35b2 | |||
| af2fdcede6 | |||
| a9f2136125 | |||
| 5d04abc0db | |||
| 26d095afda | |||
| cd030d8d12 | |||
| 4a0b7925d0 | |||
| 9d947f19b9 | |||
| 7a99beab57 | |||
| 02731c021a | |||
| fecae9d626 | |||
| a4867a1b73 | |||
| 51c2e4b568 | |||
| 756c084059 | |||
| 064973e190 | |||
| d165e9dc0f | |||
| 77109e8369 | |||
| 2924401c9b | |||
| f6c2b1129d | |||
| 8ba167a17c | |||
| 7f65b286b1 | |||
| afc9e5be0f | |||
| 7aefb555ed |
@@ -51,4 +51,11 @@ button{
|
||||
|
||||
.accordion-button, .accordion-button:not(.collapsed) {
|
||||
background-color: transparent!important;
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.modal-50 {
|
||||
min-width: 50%;
|
||||
max-width: 50%;
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import ProfileCompletePage from './views/ProfileCompletePage';
|
||||
import SubscribePage from './views/Subscribe'
|
||||
import StartPage from "./views/StartPage";
|
||||
import TrafficPage from "./views/TrafficPage";
|
||||
import MyMediaPage from './views/MyMediaPage.jsx';
|
||||
|
||||
function AppRouters() {
|
||||
return (
|
||||
@@ -52,6 +53,7 @@ function AppRouters() {
|
||||
<Route path={siteLinks.profile_complete} element={<ProfileCompletePage/>}/>
|
||||
<Route path={siteLinks.product} element={<ProductPage/>}/>
|
||||
<Route path={siteLinks.reports} element={<ReportsPage/>}/>
|
||||
<Route path={siteLinks.my_media} element={<MyMediaPage />}/>
|
||||
<Route path={siteLinks.comments} element={<CommentsPage/>}/>
|
||||
<Route path={siteLinks.contacts} element={<ContactsPage/>}/>
|
||||
<Route path={siteLinks.user} element={<UserPage/>}/>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
@@ -41,22 +41,27 @@ export default function Products() {
|
||||
</div>
|
||||
:
|
||||
<div className="row m-b-20">
|
||||
{products && products.map((product, index) => (
|
||||
<div key={product.uid+index} className={`col-xxs-6 col-xl-4 col-xxl-6 mb-2 mb-xxl-0`}>
|
||||
<Link to={productPath(product?.product_id)} >
|
||||
<div className={`d-flex align-items-center extraProductCard ${product?.icon_style}`} style={{borderColor:'black', borderWidth: '2px'}} >
|
||||
<div className="icon-container img-icon m-r-20 bg-light-gray rounded">
|
||||
<i className={`fa ${product?.product_icon} text-primary`}></i>
|
||||
{products && products.map((product, index) =>
|
||||
{
|
||||
// let productName = product?.name?.length > 14 ? product?.name?.substring(0, 14) + '...' : product?.name
|
||||
return (
|
||||
<div key={product.uid+index} className={`col-12 col-lg-6 mb-2 mb-xxl-0`}>
|
||||
<Link to={productPath(product?.product_id)} >
|
||||
<div className={`d-flex align-items-center extraProductCard ${product?.icon_style}`} style={{borderColor:'black', borderWidth: '2px'}} >
|
||||
<div className="icon-container img-icon m-r-20 bg-light-gray rounded">
|
||||
<i className={`fa ${product?.product_icon} text-primary`}></i>
|
||||
</div>
|
||||
<div className="report-details overflow-hidden">
|
||||
<p><span style={{fontWeight: 'bolder', color: '#00557A'}}>{product?.status_text}</span></p>
|
||||
<h4><span className='w-100 d-inline-block text-truncate' style={{paddingLeft: '10px'}}>{product?.name}</span></h4>
|
||||
</div>
|
||||
</div>
|
||||
<div className="report-details">
|
||||
<p><span style={{fontWeight: 'bolder', color: '#00557A'}}>{product?.status_text}</span></p>
|
||||
<h4><span className='text-truncate' style={{paddingLeft: '10px'}}>{product?.name}</span></h4>
|
||||
</div>
|
||||
</div>
|
||||
</Link>
|
||||
|
||||
</div>
|
||||
))}
|
||||
</Link>
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
<div className="apexchart-wrapper">
|
||||
|
||||
@@ -11,7 +11,7 @@ export default function UserFooter(){
|
||||
<p>© Copyright {year}. All rights reserved.</p>
|
||||
</div>
|
||||
<div className="col col-sm-6 ml-sm-auto text-center text-sm-right">
|
||||
<p>A division of <i className="fa fa-key text-danger mx-1"></i> autoMedSys A.I.</p>
|
||||
<p>A division of autoMedSys A.I.</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -48,6 +48,7 @@ export default function UserMenu() {
|
||||
</div>
|
||||
</Link>
|
||||
<ul id="collapseTwo" className="collapse" aria-labelledby="headingTwo" data-bs-parent="#sidebarNav">
|
||||
<li className={`${pathname == siteLinks.my_media ? 'active' : ''}`}><Link to={siteLinks.my_media}>Files and Media</Link></li>
|
||||
<li className={`${pathname == siteLinks.subscription ? 'active' : ''}`}><Link to={siteLinks.subscription}>Subscription</Link></li>
|
||||
<li className={`${pathname == siteLinks.settings ? 'active' : ''}`}><Link to={siteLinks.settings}>Settings</Link></li>
|
||||
</ul>
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
import React from "react";
|
||||
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||
import {useState, useRef} from "react";
|
||||
import {useQuery, useMutation, useQueryClient} from "@tanstack/react-query";
|
||||
import queryKeys from "../../services/queryKeys";
|
||||
import {getMediaFileList, uploadFile} from "../../services/services";
|
||||
import getImage from "../../utils/getImage";
|
||||
|
||||
|
||||
export default function MyMedia() {
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const basePath = process.env.REACT_APP_MAIN_API
|
||||
const [selectedFile, setSelectedFile] = useState(null);
|
||||
const [message, setMessage] = useState('');
|
||||
const [imageLink, setImageLink] = useState('')
|
||||
console.log('imageLink', imageLink)
|
||||
// Function to handle file selection
|
||||
const handleFileChange = (event) => {
|
||||
setSelectedFile(event.target.files[0]);
|
||||
setMessage('');
|
||||
};
|
||||
|
||||
// Function to handle the upload to the API
|
||||
const _handleUpload = async () => {
|
||||
if (!selectedFile) {
|
||||
setMessage('Please select a file first!');
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
// 'file' is the field name that your API endpoint expects
|
||||
formData.append('file', selectedFile);
|
||||
formData.append("member_uid", localStorage.getItem('uid'));
|
||||
formData.append("token", localStorage.getItem('token'));
|
||||
|
||||
try {
|
||||
// Replace with your actual API endpoint URL
|
||||
const apiEndpoint = basePath + '/upload/webfiles';
|
||||
const response = await fetch(apiEndpoint, {
|
||||
method: 'POST',
|
||||
// The browser automatically sets the 'Content-Type' header to
|
||||
// 'multipart/form-data' when you provide a FormData object as the body,
|
||||
// which is required for file uploads.
|
||||
body: formData,
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const result = await response.json();
|
||||
setMessage('File uploaded successfully!');
|
||||
console.log('Success:', result);
|
||||
} else {
|
||||
setMessage('Upload failed.');
|
||||
console.error('Upload failed:', response.statusText);
|
||||
}
|
||||
} catch (error) {
|
||||
setMessage('An error occurred during the upload.');
|
||||
console.error('Error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
const uploadFileMutation = useMutation({
|
||||
mutationFn: (fields) => {
|
||||
if(!fields.file){
|
||||
throw({message: 'Please select a file first!'})
|
||||
}
|
||||
return uploadFile(fields)
|
||||
},
|
||||
onSuccess: (res) => {
|
||||
// console.log('res', res.data)
|
||||
// if(res.data.resultCode != '0' || !res?.data?.pending_uid){
|
||||
// throw({message: res?.data?.resultDescription})
|
||||
// }
|
||||
setSelectedFile(null)
|
||||
queryClient.refetchQueries({
|
||||
queryKey: [...queryKeys.my_files],
|
||||
// type: 'active',
|
||||
// exact: true,
|
||||
})
|
||||
},
|
||||
onSettled: () => {
|
||||
setTimeout(()=>{
|
||||
uploadFileMutation.reset()
|
||||
}, 3000)
|
||||
}
|
||||
})
|
||||
|
||||
const handleUpload = () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem("token"), // USER TOKEN
|
||||
member_uid: localStorage.getItem("uid"), // USER UID
|
||||
file: selectedFile
|
||||
};
|
||||
// console.log(reqData)
|
||||
uploadFileMutation.mutate(reqData)
|
||||
}
|
||||
|
||||
const {data, isFetching, isError, error} = useQuery({
|
||||
queryKey: queryKeys.my_files,
|
||||
queryFn: () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid') // USER UID
|
||||
}
|
||||
return getMediaFileList(reqData)
|
||||
}
|
||||
})
|
||||
|
||||
const mediaFileList = data?.data
|
||||
|
||||
//debugger;
|
||||
|
||||
return (
|
||||
<>
|
||||
<BreadcrumbComBS title='Files' paths={['Dashboard', 'Files']}/>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-xl-6 col-xxl-4 m-b-30">
|
||||
<div className="card card-statistics mb-0 widget-support-list">
|
||||
<div className="card-header">
|
||||
<div className="card-heading">
|
||||
<h4 className="card-title">Upload File</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-body pl-0 pr-0 scrollbar scroll_dark">
|
||||
<div className="widget-text">
|
||||
|
||||
<div>
|
||||
<input className="form-control form-control-sm" type="file"
|
||||
onChange={handleFileChange}/>
|
||||
|
||||
{selectedFile && (
|
||||
<div>
|
||||
<h4>Selected File Details:</h4>
|
||||
<ul>
|
||||
<li>Name: {selectedFile.name}</li>
|
||||
<li>Type: {selectedFile.type}</li>
|
||||
<li>Size: {selectedFile.size} bytes</li>
|
||||
</ul>
|
||||
<div style={{width: '100%', textAlign: 'right'}}>
|
||||
<button
|
||||
className="btn btn-square btn-inverse-light btn-xs d-inline-block mt-2 mb-0"
|
||||
onClick={handleUpload} disabled={!selectedFile || uploadFileMutation.isPending || uploadFileMutation.isSuccess}>
|
||||
Upload
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<>
|
||||
{/* {message && <p>{message}</p>} */}
|
||||
<p>{uploadFileMutation.isPending ? 'uploading...' : uploadFileMutation.isError ? uploadFileMutation?.error?.message : uploadFileMutation.isSuccess ? 'File Uploaded' : ''}</p>
|
||||
</>
|
||||
</div>
|
||||
|
||||
)}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-xl-6 col-xxl-4 m-b-30">
|
||||
<div className="card card-statistics h-100 mb-0 widget-downloads-list" style={{}}>
|
||||
<div className="card-header d-flex justify-content-between">
|
||||
<div className="card-heading">
|
||||
<div className="card-heading">
|
||||
<h4 className="card-title">Files List</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{isFetching ?
|
||||
<>
|
||||
<div className="col-12">
|
||||
<p className='text-mute'>Loading...</p>
|
||||
</div>
|
||||
</>
|
||||
: isError ?
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{error?.message}</p>
|
||||
</div>
|
||||
:
|
||||
<div className="card-body scrollbar scroll_dark" style={{minHeight: '400px', maxHeight: '500px', overflowY: 'auto'}}>
|
||||
{mediaFileList && mediaFileList?.file_list && mediaFileList?.file_list.map((item, index) => {
|
||||
const file_url = (mediaFileList?.media_server + "/" + item?.file_group + "/" + item?.file_uid + "/" + item.filename).toLowerCase();
|
||||
const avtarImage =
|
||||
item?.file_type === undefined
|
||||
? "icons/01.png"
|
||||
: "icons/" + item.file_type + ".png";
|
||||
return (<div key={index} className={`widget-text ${imageLink == file_url && 'bg-light'}`}>
|
||||
<div className={`media align-items-center`} onClick={()=>setImageLink(file_url)} style={{cursor: 'pointer'}}>
|
||||
<img src={getImage(avtarImage)}
|
||||
// src={`assets/img/file-icon/${item.file_type}.png`}
|
||||
className="img-fluid"
|
||||
alt={`${item.file_type}`}/>
|
||||
<div className="media-body">
|
||||
<h4 className="mb-0 ml-3">{item.filename}</h4>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a href={`${file_url}`} target='_blank'
|
||||
className="btn btn-icon btn-round btn-outline-success">
|
||||
<i className="ti ti-download"></i>
|
||||
</a>
|
||||
<a href="" className="btn btn-icon btn-round btn-outline-danger ml-2">
|
||||
<i className="ti ti-close"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-xl-6 col-xxl-4 m-b-30">
|
||||
<div className="card card-statistics h-100 mb-0 widget-branches-list">
|
||||
<div className="card-header">
|
||||
<div className="card-heading">
|
||||
<h4 className="card-title">Preview</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-body d-flex justify-content-center align-items-center pl-0 pr-0 scrollbar scroll_dark">
|
||||
{imageLink &&
|
||||
<img className="w-100 h-auto" src={imageLink} alt='file-image' />
|
||||
}
|
||||
</div>
|
||||
<div className="card-header d-flex justify-content-between align-items-center">
|
||||
{imageLink &&
|
||||
<>
|
||||
<p>0 x 0 px</p>
|
||||
<p>size: 0 bytes</p>
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -66,7 +66,7 @@ export default function ProductActive({productData}){
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="card-body" style={{minHeight: '680px'}}>
|
||||
<div className="card-body" style={{minHeight: '600px', maxHeight: '600px'}}>
|
||||
<iframe ref={iframe} style={{borderWidth: '0px'}} src={externalUrl} width="100%" height="600" title={externalUrl}></iframe>
|
||||
</div>
|
||||
<div className="p-4 ml-auto">
|
||||
|
||||
@@ -5,6 +5,7 @@ import queryKeys from '../../../services/queryKeys';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import sortObjectByListOrder from '../../../helpers/sortObjectByListOrder'
|
||||
import TemplateConfigure from './TemplateConfigure';
|
||||
|
||||
const Settings = memo(({productData}) => {
|
||||
|
||||
@@ -24,7 +25,7 @@ const Settings = memo(({productData}) => {
|
||||
})
|
||||
const settingsConfig = configData?.data?.settings_items
|
||||
// console.log('CONFIG DATA...', settingsConfig)
|
||||
|
||||
// console.log('configData', configData?.data?.subscription_template)
|
||||
|
||||
const [fieldsChanged, setFieldsChanged] = useState(false)
|
||||
|
||||
@@ -81,12 +82,12 @@ const Settings = memo(({productData}) => {
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
<div className="tab tab-vertical">
|
||||
<ul className="nav nav-tabs" role="tablist">
|
||||
<div className="d-flex">
|
||||
<ul className="bg-body-secondary flex-column nav" role="tablist" style={{width: '25%', minHeight: '670px', maxHeight: '670px'}}>
|
||||
<>
|
||||
{Object.entries(sortedSettingsConfig).map(([key, value], index) => (
|
||||
<li key={key} className="nav-item">
|
||||
<a className={`nav-link ${(activeTab == value.controls || (index == 0 & !activeTab)) && 'active show'}`}
|
||||
<p className={`text-black nav-link ${(activeTab == value.controls || (index == 0 & !activeTab)) && 'active show bg-primary text-white'}`}
|
||||
id={key}
|
||||
// data-bs-toggle="pill"
|
||||
// data-bs-target={`#${value.controls}`}
|
||||
@@ -97,12 +98,27 @@ const Settings = memo(({productData}) => {
|
||||
onClick={()=>handleChangeTab(value.controls)}
|
||||
>
|
||||
{value.title}
|
||||
</a>
|
||||
</p>
|
||||
</li>
|
||||
))}
|
||||
{configData?.data?.subscription_template &&
|
||||
<li className="mt-auto nav-item">
|
||||
<p className={`text-black nav-link ${(activeTab == 'config_temp') && 'active show bg-primary text-white'}`}
|
||||
// data-bs-toggle="pill"
|
||||
// data-bs-target={`#${value.controls}`}
|
||||
type="button"
|
||||
// role="tab"
|
||||
// aria-controls={value.controls}
|
||||
// aria-selected="true"
|
||||
onClick={()=>handleChangeTab('config_temp')}
|
||||
>
|
||||
Configure Template
|
||||
</p>
|
||||
</li>
|
||||
}
|
||||
</>
|
||||
</ul>
|
||||
<div className="tab-content">
|
||||
<div className="p-3 tab-content" style={{width: '75%'}}>
|
||||
<>
|
||||
{Object.entries(sortedSettingsConfig).map(([key, value], index) => (
|
||||
<div key={key} className={`tab-pane fade ${(activeTab == value.controls || (index == 0 & !activeTab)) && 'active show'}`}
|
||||
@@ -112,6 +128,10 @@ const Settings = memo(({productData}) => {
|
||||
<GeneralTab tabKey={key} name={value.title} data={value.data} isCustom={value.custom} productData={productData} backendValues={settingsData} setFieldsChanged={setFieldsChanged} />
|
||||
</div>
|
||||
))}
|
||||
<div className={`tab-pane fade ${(activeTab == 'config_temp') && 'active show'}`}
|
||||
>
|
||||
<TemplateConfigure productData={productData} />
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
import React, {memo, useState} from 'react'
|
||||
import getImage from "../../../utils/getImage";
|
||||
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query';
|
||||
import queryKeys from '../../../services/queryKeys';
|
||||
import {getTemplateConfig} from '../../../services/services';
|
||||
import {Link} from "react-router-dom";
|
||||
import siteLinks from "../../../links/siteLinks";
|
||||
import UploadModal from './UploadModal';
|
||||
|
||||
const TemplateConfigure = ({productData}) => {
|
||||
|
||||
const [selectedSectionDetails, setSelectedSectionDetails] = useState({})
|
||||
|
||||
// /panel/myproduct/template-config
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const {data: templateData, isFetching, isError, error} = useQuery({
|
||||
queryKey: queryKeys.myTemplateConfig,
|
||||
queryFn: () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid'), // USER UID
|
||||
product_id: productData?.product_id
|
||||
}
|
||||
return getTemplateConfig(reqData)
|
||||
},
|
||||
staleTime: 0
|
||||
})
|
||||
|
||||
const templateResponse = templateData?.data
|
||||
const templateImages = templateResponse?.template_images?.data;
|
||||
// debugger;
|
||||
console.log("templateResponse", templateResponse);
|
||||
// const currentColorUID = templateResponse?.current_colorstyle_uid
|
||||
// const color_styles = templateResponse?.color_styles
|
||||
// const custom_template_name = templateResponse?.custom_template_name
|
||||
|
||||
return <>
|
||||
<div className="card card-statistics">
|
||||
{isFetching ?
|
||||
<>
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<p className='text-mute'>Loading...</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
: isError ?
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{error?.message}</p>
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
<>
|
||||
<div className="card-header">
|
||||
<div className="card-heading">
|
||||
<h4 className="card-title"
|
||||
style={{textTransform: 'none'}}>{templateResponse?.template_name}</h4>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<div className="col-12">
|
||||
<div>
|
||||
<div>
|
||||
<div>
|
||||
<h4>Image List</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<ul className="list-unstyled">
|
||||
{templateImages && templateImages.map(
|
||||
(item) => {
|
||||
const currImage = item?.default_val;
|
||||
return (
|
||||
<li className="media">
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
padding: '5px',
|
||||
backgroundColor: 'aliceblue',
|
||||
margin: '2px',
|
||||
maxHeight: '150px'
|
||||
}}>
|
||||
<div className='d-flex justify-content-center align-items-center' style={{padding: '6px', width: '120px', height: '100px'}}>
|
||||
<img className="mb-xxs-0 img-fluid"
|
||||
style={{height: 'auto', maxHeight: '100px'}}
|
||||
src={currImage} alt="image"/>
|
||||
</div>
|
||||
|
||||
<div className="media-body" style={{padding: '2px'}}>
|
||||
<div style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
}}>
|
||||
<div style={{textAlign: 'right',width: '100%'}}></div>
|
||||
{/* [Change Image] */}
|
||||
<label onClick={()=>setSelectedSectionDetails(item)} className='w-100 text-end' data-bs-toggle="modal" data-bs-target="#verticalCenter" style={{cursor: 'pointer'}}>[Change Image]</label>
|
||||
{/* <input id={item?.id} name={item?.id} className="d-none form-control form-control-sm" type="file" onChange={handleFileChange}/> */}
|
||||
<div>
|
||||
<h5 className="mt-0 mb-1">{item?.name}</h5>
|
||||
{item?.description}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</li>
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</>
|
||||
|
||||
|
||||
} </div>
|
||||
<UploadModal productId={productData?.product_id} selectedSectionDetails={selectedSectionDetails} />
|
||||
</>
|
||||
}
|
||||
|
||||
export default TemplateConfigure
|
||||
@@ -0,0 +1,168 @@
|
||||
import React, { useRef, useState } from 'react'
|
||||
import { Modal } from "bootstrap";
|
||||
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query';
|
||||
import queryKeys from '../../../services/queryKeys';
|
||||
import {getMediaFileList, templateMediaSet} from '../../../services/services';
|
||||
|
||||
export default function UploadModal({productId, selectedSectionDetails}) {
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const [selectedFile, setSelectedFile] = useState('')
|
||||
|
||||
const handleSelectedFile = (file_uid) => {
|
||||
// if(selectedFile.length && selectedFile.includes(file_uid)){
|
||||
// let indexOfItem = selectedFile.indexOf(file_uid)
|
||||
// let oldFiles = [...selectedFile]
|
||||
// oldFiles.splice(indexOfItem, 1)
|
||||
// setSelectedFile(oldFiles)
|
||||
// }else{
|
||||
// setSelectedFile(prev => [...prev, file_uid])
|
||||
// }
|
||||
setSelectedFile(file_uid)
|
||||
}
|
||||
|
||||
const modalRef = useRef(null)
|
||||
|
||||
const dismissModal = () => {
|
||||
const body = document.querySelector('body')
|
||||
body.removeAttribute('style')
|
||||
// body.classList.toggle('modal-open')
|
||||
|
||||
const modalBackdrop = document.querySelectorAll('.modal-backdrop')
|
||||
modalBackdrop.forEach(item => {
|
||||
if (item) {
|
||||
item.remove();
|
||||
}
|
||||
})
|
||||
|
||||
const modal = Modal.getInstance(modalRef.current);
|
||||
modal && modal.hide();
|
||||
};
|
||||
|
||||
const changeTemplateMediaSet = useMutation({
|
||||
mutationFn: (fields) => {
|
||||
if(!fields.file_uid){
|
||||
throw({message: 'Please select a file first!'})
|
||||
}
|
||||
return templateMediaSet(fields)
|
||||
},
|
||||
onSuccess: (res) => {
|
||||
// console.log('res', res.data)
|
||||
if(res.data.resultCode != '0'){
|
||||
throw({message: res?.data?.resultDescription})
|
||||
}
|
||||
setSelectedFile('')
|
||||
dismissModal() // to close modal
|
||||
queryClient.refetchQueries({
|
||||
queryKey: [...queryKeys.myTemplateConfig],
|
||||
// type: 'active',
|
||||
// exact: true,
|
||||
})
|
||||
},
|
||||
onSettled: () => {
|
||||
setTimeout(()=>{
|
||||
changeTemplateMediaSet.reset()
|
||||
}, 3000)
|
||||
}
|
||||
})
|
||||
|
||||
const handleUpload = () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem("token"), // USER TOKEN
|
||||
uid: localStorage.getItem("uid"), // USER UID
|
||||
product_id: productId,
|
||||
file_uid: selectedFile,
|
||||
image_id: selectedSectionDetails?.id
|
||||
};
|
||||
// console.log('reqData', reqData)
|
||||
changeTemplateMediaSet.mutate(reqData)
|
||||
}
|
||||
|
||||
const {data, isFetching, isError, error} = useQuery({
|
||||
queryKey: queryKeys.my_files,
|
||||
queryFn: () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid') // USER UID
|
||||
}
|
||||
return getMediaFileList(reqData)
|
||||
}
|
||||
})
|
||||
|
||||
const mediaFileList = data?.data
|
||||
// console.log('mediaFileList', mediaFileList) //file_list
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Vertical Center Modal */}
|
||||
<div ref={modalRef} className="modal fade" id="verticalCenter" tabIndex="-1" role="dialog" aria-hidden="false">
|
||||
<div className="modal-50 modal-dialog modal-dialog-centered modal-50" role="document">
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
<h5 className="modal-title" style={{fontSize: '18px'}} id="verticalCenterTitle">Select New Picture</h5>
|
||||
<button type="button" className="close" data-bs-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
{isFetching ?
|
||||
<>
|
||||
<div className="col-12">
|
||||
<p className='text-mute'>Loading...</p>
|
||||
</div>
|
||||
</>
|
||||
: isError ?
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{error?.message}</p>
|
||||
</div>
|
||||
:
|
||||
<div className='row g-5 justify-content-center'>
|
||||
{mediaFileList?.file_list?.length ?
|
||||
<>
|
||||
{mediaFileList?.file_list?.map(item => {
|
||||
const file_url = (mediaFileList?.media_server + "/" + item?.file_group + "/" + item?.file_uid + "/" + item.filename).toLowerCase();
|
||||
return(
|
||||
<div onClick={()=>handleSelectedFile(item?.file_uid)} className={`p-3 text-center col-4`} style={{cursor: 'pointer'}}>
|
||||
<div className={`p-3 ${(selectedFile == item?.file_uid) && 'bg-light'}`} style={{Height: '250px'}}>
|
||||
<img key={item?.file_uid} className="img-fluid" style={{}} src={file_url} alt='file-image' />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</>
|
||||
:
|
||||
<p>No File(s) found!</p>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
{changeTemplateMediaSet.error &&
|
||||
<>
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{changeTemplateMediaSet.error.message}</p>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
{changeTemplateMediaSet.isSuccess &&
|
||||
<>
|
||||
<div className="col-12">
|
||||
<p className='text-success'>{'subscription is successful'}</p>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
</div>
|
||||
<div className="modal-footer">
|
||||
<button type="button" className="btn btn-danger" data-bs-dismiss="modal">Cancel</button>
|
||||
{selectedFile &&
|
||||
<button type="button" className="btn btn-primary" disabled={changeTemplateMediaSet?.isPending || changeTemplateMediaSet?.isSuccess} onClick={handleUpload}>{changeTemplateMediaSet?.isPending ? 'Applying...' : changeTemplateMediaSet?.isSuccess ? 'Applied' : 'Apply'}</button>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* END of Vertical Center Modal */}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
import React, { useState } from "react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getPaymentReports } from "../../services/services";
|
||||
import queryKeys from "../../services/queryKeys";
|
||||
|
||||
export default function PaymentReportTable() {
|
||||
|
||||
const [page, setPage] = useState(0)
|
||||
|
||||
const {data, isFetching, isError, error} = useQuery({
|
||||
queryKey: [...queryKeys.payment_report, page],
|
||||
queryFn: () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid'), // USER UID
|
||||
page
|
||||
}
|
||||
return getPaymentReports(reqData)
|
||||
}
|
||||
})
|
||||
|
||||
console.log('DATA', data?.data)
|
||||
return (
|
||||
<>
|
||||
<div className="row">
|
||||
<div className="col-md-12 m-b-30">
|
||||
<div className="d-block d-sm-flex flex-nowrap align-items-center">
|
||||
<div className="page-title mb-2 mb-sm-0">
|
||||
<h4>Payments Report</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row">
|
||||
{isFetching ?
|
||||
<>
|
||||
<div className="col-12">
|
||||
<p className='text-mute'>Loading...</p>
|
||||
</div>
|
||||
</>
|
||||
: isError ?
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{error?.message}</p>
|
||||
</div>
|
||||
:
|
||||
<div className="col-lg-12">
|
||||
<div className="card card-statistics">
|
||||
<div className="card-body">
|
||||
<div className="export-table-wrapper table-responsive">
|
||||
<table id="export-table" className="table table-bordered">
|
||||
<thead className="thead-light">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Position</th>
|
||||
<th>Office</th>
|
||||
<th>Age</th>
|
||||
<th>Start date</th>
|
||||
<th>Salary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Tiger Nixon</td>
|
||||
<td>System Architect</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>61</td>
|
||||
<td>2011/04/25</td>
|
||||
<td>$320,800</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Garrett Winters</td>
|
||||
<td>Accountant</td>
|
||||
<td>Tokyo</td>
|
||||
<td>63</td>
|
||||
<td>2011/07/25</td>
|
||||
<td>$170,750</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ashton Cox</td>
|
||||
<td>Junior Technical Author</td>
|
||||
<td>San Francisco</td>
|
||||
<td>66</td>
|
||||
<td>2009/01/12</td>
|
||||
<td>$86,000</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cedric Kelly</td>
|
||||
<td>Senior Javascript Developer</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>22</td>
|
||||
<td>2012/03/29</td>
|
||||
<td>$433,060</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Airi Satou</td>
|
||||
<td>Accountant</td>
|
||||
<td>Tokyo</td>
|
||||
<td>33</td>
|
||||
<td>2008/11/28</td>
|
||||
<td>$162,700</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Brielle Williamson</td>
|
||||
<td>Integration Specialist</td>
|
||||
<td>New York</td>
|
||||
<td>61</td>
|
||||
<td>2012/12/02</td>
|
||||
<td>$372,000</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Herrod Chandler</td>
|
||||
<td>Sales Assistant</td>
|
||||
<td>San Francisco</td>
|
||||
<td>59</td>
|
||||
<td>2012/08/06</td>
|
||||
<td>$137,500</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Rhona Davidson</td>
|
||||
<td>Integration Specialist</td>
|
||||
<td>Tokyo</td>
|
||||
<td>55</td>
|
||||
<td>2010/10/14</td>
|
||||
<td>$327,900</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Colleen Hurst</td>
|
||||
<td>Javascript Developer</td>
|
||||
<td>San Francisco</td>
|
||||
<td>39</td>
|
||||
<td>2009/09/15</td>
|
||||
<td>$205,500</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sonya Frost</td>
|
||||
<td>Software Engineer</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>23</td>
|
||||
<td>2008/12/13</td>
|
||||
<td>$103,600</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Jena Gaines</td>
|
||||
<td>Office Manager</td>
|
||||
<td>London</td>
|
||||
<td>30</td>
|
||||
<td>2008/12/19</td>
|
||||
<td>$90,560</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Quinn Flynn</td>
|
||||
<td>Support Lead</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>22</td>
|
||||
<td>2013/03/03</td>
|
||||
<td>$342,000</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Charde Marshall</td>
|
||||
<td>Regional Director</td>
|
||||
<td>San Francisco</td>
|
||||
<td>36</td>
|
||||
<td>2008/10/16</td>
|
||||
<td>$470,600</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Haley Kennedy</td>
|
||||
<td>Senior Marketing Designer</td>
|
||||
<td>London</td>
|
||||
<td>43</td>
|
||||
<td>2012/12/18</td>
|
||||
<td>$313,500</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tatyana Fitzpatrick</td>
|
||||
<td>Regional Director</td>
|
||||
<td>London</td>
|
||||
<td>19</td>
|
||||
<td>2010/03/17</td>
|
||||
<td>$385,750</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Michael Silva</td>
|
||||
<td>Marketing Designer</td>
|
||||
<td>London</td>
|
||||
<td>66</td>
|
||||
<td>2012/11/27</td>
|
||||
<td>$198,500</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
import React, { useState } from "react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getProductReports } from "../../services/services";
|
||||
import queryKeys from "../../services/queryKeys";
|
||||
|
||||
export default function ProductReportTable() {
|
||||
|
||||
const [page, setPage] = useState(0)
|
||||
|
||||
const {data, isFetching, isError, error} = useQuery({
|
||||
queryKey: [...queryKeys.product_report, page],
|
||||
queryFn: () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid'), // USER UID
|
||||
page
|
||||
}
|
||||
return getProductReports(reqData)
|
||||
}
|
||||
})
|
||||
|
||||
console.log('DATA', data?.data)
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-md-12 m-b-30">
|
||||
<div className="d-block d-sm-flex flex-nowrap align-items-center">
|
||||
<div className="page-title mb-2 mb-sm-0">
|
||||
<h4>Products Report</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
{isFetching ?
|
||||
<>
|
||||
<div className="col-12">
|
||||
<p className='text-mute'>Loading...</p>
|
||||
</div>
|
||||
</>
|
||||
: isError ?
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{error?.message}</p>
|
||||
</div>
|
||||
:
|
||||
<div className="col-lg-12">
|
||||
<div className="card card-statistics">
|
||||
<div className="card-body">
|
||||
<div className="export-table-wrapper table-responsive">
|
||||
<table id="export-table" className="table table-bordered">
|
||||
<thead className="thead-light">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Position</th>
|
||||
<th>Office</th>
|
||||
<th>Age</th>
|
||||
<th>Start date</th>
|
||||
<th>Salary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Tiger Nixon</td>
|
||||
<td>System Architect</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>61</td>
|
||||
<td>2011/04/25</td>
|
||||
<td>$320,800</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Garrett Winters</td>
|
||||
<td>Accountant</td>
|
||||
<td>Tokyo</td>
|
||||
<td>63</td>
|
||||
<td>2011/07/25</td>
|
||||
<td>$170,750</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ashton Cox</td>
|
||||
<td>Junior Technical Author</td>
|
||||
<td>San Francisco</td>
|
||||
<td>66</td>
|
||||
<td>2009/01/12</td>
|
||||
<td>$86,000</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cedric Kelly</td>
|
||||
<td>Senior Javascript Developer</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>22</td>
|
||||
<td>2012/03/29</td>
|
||||
<td>$433,060</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Airi Satou</td>
|
||||
<td>Accountant</td>
|
||||
<td>Tokyo</td>
|
||||
<td>33</td>
|
||||
<td>2008/11/28</td>
|
||||
<td>$162,700</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Brielle Williamson</td>
|
||||
<td>Integration Specialist</td>
|
||||
<td>New York</td>
|
||||
<td>61</td>
|
||||
<td>2012/12/02</td>
|
||||
<td>$372,000</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Herrod Chandler</td>
|
||||
<td>Sales Assistant</td>
|
||||
<td>San Francisco</td>
|
||||
<td>59</td>
|
||||
<td>2012/08/06</td>
|
||||
<td>$137,500</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Rhona Davidson</td>
|
||||
<td>Integration Specialist</td>
|
||||
<td>Tokyo</td>
|
||||
<td>55</td>
|
||||
<td>2010/10/14</td>
|
||||
<td>$327,900</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Colleen Hurst</td>
|
||||
<td>Javascript Developer</td>
|
||||
<td>San Francisco</td>
|
||||
<td>39</td>
|
||||
<td>2009/09/15</td>
|
||||
<td>$205,500</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sonya Frost</td>
|
||||
<td>Software Engineer</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>23</td>
|
||||
<td>2008/12/13</td>
|
||||
<td>$103,600</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Jena Gaines</td>
|
||||
<td>Office Manager</td>
|
||||
<td>London</td>
|
||||
<td>30</td>
|
||||
<td>2008/12/19</td>
|
||||
<td>$90,560</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Quinn Flynn</td>
|
||||
<td>Support Lead</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>22</td>
|
||||
<td>2013/03/03</td>
|
||||
<td>$342,000</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Charde Marshall</td>
|
||||
<td>Regional Director</td>
|
||||
<td>San Francisco</td>
|
||||
<td>36</td>
|
||||
<td>2008/10/16</td>
|
||||
<td>$470,600</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Haley Kennedy</td>
|
||||
<td>Senior Marketing Designer</td>
|
||||
<td>London</td>
|
||||
<td>43</td>
|
||||
<td>2012/12/18</td>
|
||||
<td>$313,500</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tatyana Fitzpatrick</td>
|
||||
<td>Regional Director</td>
|
||||
<td>London</td>
|
||||
<td>19</td>
|
||||
<td>2010/03/17</td>
|
||||
<td>$385,750</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Michael Silva</td>
|
||||
<td>Marketing Designer</td>
|
||||
<td>London</td>
|
||||
<td>66</td>
|
||||
<td>2012/11/27</td>
|
||||
<td>$198,500</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,62 +1,92 @@
|
||||
import React from "react";
|
||||
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||
import {useQuery} from "@tanstack/react-query";
|
||||
import queryKeys from "../../services/queryKeys";
|
||||
import {getReportsTopicsList} from "../../services/services";
|
||||
import PaymentReportTable from "./PaymentReportTable";
|
||||
import ProductReportTable from "./ProductReportTable";
|
||||
import sortArrayByListOrder from "../../helpers/sortArrayByLIstOrder";
|
||||
import SystemReportTable from "./SystemReportTable";
|
||||
|
||||
|
||||
export default function Reports(){
|
||||
export default function Reports() {
|
||||
|
||||
return(
|
||||
const {data, isFetching, isError, error} = useQuery({
|
||||
queryKey: queryKeys.topics,
|
||||
queryFn: () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid') // USER UID
|
||||
}
|
||||
return getReportsTopicsList(reqData)
|
||||
}
|
||||
})
|
||||
|
||||
const reportTopicList = data?.data?.topics?.topics;
|
||||
|
||||
const renderedTable = {
|
||||
payment: <PaymentReportTable />,
|
||||
product: <ProductReportTable />,
|
||||
system: <SystemReportTable />
|
||||
}
|
||||
|
||||
const sortedReportTopicList= sortArrayByListOrder(reportTopicList ? reportTopicList : []) // SORTED SETTINGSCONFIG
|
||||
|
||||
return (
|
||||
<>
|
||||
<BreadcrumbComBS title='Reports' paths={['Dashboard', 'Reports']} />
|
||||
<BreadcrumbComBS title='Reports' paths={['Dashboard', 'Reports']}/>
|
||||
<div className="row">
|
||||
|
||||
|
||||
{isFetching ?
|
||||
<>
|
||||
<div className="col-12">
|
||||
<p className='text-mute'>Loading...</p>
|
||||
</div>
|
||||
</>
|
||||
: isError ?
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{error?.message}</p>
|
||||
</div>
|
||||
:
|
||||
<div>
|
||||
<div>
|
||||
<div className="card card-statistics" style={{minHeight: '550px'}}>
|
||||
{/*<div className="card-header">*/}
|
||||
{/* <div className="card-heading">*/}
|
||||
{/* <h4 className="card-title"> Tab vertical </h4>*/}
|
||||
{/* </div>*/}
|
||||
{/*</div>*/}
|
||||
<div className="card-body">
|
||||
<div className="tab tab-vertical">
|
||||
|
||||
{/* <!-- Tabs --> */}
|
||||
<ul className="nav nav-tabs" id="myTab" role="tablist">
|
||||
{sortedReportTopicList && sortedReportTopicList.map((item, index) => {
|
||||
return (
|
||||
<li key={index} className="nav-item" role="presentation">
|
||||
<a className={`nav-link ${index == 0 && 'active'}`} id={`tab-${item?.url}`} href="#" data-bs-toggle="tab" data-bs-target={`#content-${item?.url}`} type="button" role="tab">
|
||||
{item?.name}
|
||||
</a>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
</ul>
|
||||
|
||||
<div>
|
||||
|
||||
<div className="card card-statistics" style={{minHeight:'550px'}}>
|
||||
{/*<div className="card-header">*/}
|
||||
{/* <div className="card-heading">*/}
|
||||
{/* <h4 className="card-title"> Tab vertical </h4>*/}
|
||||
{/* </div>*/}
|
||||
{/*</div>*/}
|
||||
<div className="card-body">
|
||||
<div className="tab tab-vertical">
|
||||
<ul className="nav nav-tabs" role="tablist">
|
||||
<li className="nav-item">
|
||||
<a className="nav-link active show" id="home-09-tab" data-toggle="tab" href="#home-09" role="tab" aria-controls="home-09" aria-selected="true"> Home</a>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<a className="nav-link" id="profile-09-tab" data-toggle="tab" href="#profile-09" role="tab" aria-controls="profile-09" aria-selected="false"> Profile </a>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<a className="nav-link" id="portfolio-09-tab" data-toggle="tab" href="#portfolio-09" role="tab" aria-controls="portfolio-09" aria-selected="false">Portfolio </a>
|
||||
</li>
|
||||
<li className="nav-item">
|
||||
<a className="nav-link" id="contact-09-tab" data-toggle="tab" href="#contact-09" role="tab" aria-controls="contact-09" aria-selected="false"> Contact </a>
|
||||
</li>
|
||||
</ul>
|
||||
<div className="tab-content">
|
||||
<div className="tab-pane fade active show" id="home-09" role="tabpanel" aria-labelledby="home-09-tab">
|
||||
<p>Positive pleasure-oriented goals are much more powerful motivators than negative fear-based ones. Although each is successful separately, the right combination of both is the most powerful motivational force known to humankind.Make a list of your achievements toward your long-term goal and remind yourself that intentions don’t count, only action’s.</p>
|
||||
</div>
|
||||
<div className="tab-pane fade" id="profile-09" role="tabpanel" aria-labelledby="profile-09-tab">
|
||||
<p>Reflect and experiment until you find the right combination of motivators for your personality and your personal goals. Do it today. Remind yourself of someone you know who died suddenly and the fact that there is no guarantee that tomorrow will come.</p>
|
||||
</div>
|
||||
<div className="tab-pane fade" id="portfolio-09" role="tabpanel" aria-labelledby="portfolio-09-tab">
|
||||
<p>Commitment is something that comes from understanding that everything has its price and then having the willingness to pay that price. This is important because nobody wants to put significant effort into something, only to find out after the fact that the price was too high. We all know people who live this truth.Give yourself the power of responsibility.</p>
|
||||
</div>
|
||||
<div className="tab-pane fade" id="contact-09" role="tabpanel" aria-labelledby="contact-09-tab">
|
||||
<p>I truly believe Augustine’s words are true and if you look at history you know it is true. There are many people in the world with amazing talents who realize only a small percentage of their potential. We all know people who live this truth.Give yourself the power of responsibility. Remind yourself the only thing stopping you is yourself.</p>
|
||||
</div>
|
||||
</div>
|
||||
{/* <!-- Tab Content --> */}
|
||||
<div className="tab-content">
|
||||
{sortedReportTopicList && sortedReportTopicList.map((item, index) => {
|
||||
return (
|
||||
<div key={index} className={`tab-pane fade show ${index == 0 && 'active'}`} id={`content-${item?.url}`} role="tabpanel">
|
||||
{renderedTable[item?.url]}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
import React, { useState } from "react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getSystemReports } from "../../services/services";
|
||||
import queryKeys from "../../services/queryKeys";
|
||||
|
||||
export default function SystemReportTable() {
|
||||
|
||||
const [page, setPage] = useState(0)
|
||||
|
||||
const {data, isFetching, isError, error} = useQuery({
|
||||
queryKey: [...queryKeys.system_report, page],
|
||||
queryFn: () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid'), // USER UID
|
||||
page
|
||||
}
|
||||
return getSystemReports(reqData)
|
||||
},
|
||||
})
|
||||
|
||||
console.log('DATA', data?.data)
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
<div className="row">
|
||||
<div className="col-md-12 m-b-30">
|
||||
<div className="d-block d-sm-flex flex-nowrap align-items-center">
|
||||
<div className="page-title mb-2 mb-sm-0">
|
||||
<h4>Systems Report</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row">
|
||||
{isFetching ?
|
||||
<>
|
||||
<div className="col-12">
|
||||
<p className='text-mute'>Loading...</p>
|
||||
</div>
|
||||
</>
|
||||
: isError ?
|
||||
<div className="col-12">
|
||||
<p className='text-danger'>{error?.message}</p>
|
||||
</div>
|
||||
:
|
||||
<div className="col-lg-12">
|
||||
<div className="card card-statistics">
|
||||
<div className="card-body">
|
||||
<div className="export-table-wrapper table-responsive">
|
||||
<table id="export-table" className="table table-bordered">
|
||||
<thead className="thead-light">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Position</th>
|
||||
<th>Office</th>
|
||||
<th>Age</th>
|
||||
<th>Start date</th>
|
||||
<th>Salary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Tiger Nixon</td>
|
||||
<td>System Architect</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>61</td>
|
||||
<td>2011/04/25</td>
|
||||
<td>$320,800</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Garrett Winters</td>
|
||||
<td>Accountant</td>
|
||||
<td>Tokyo</td>
|
||||
<td>63</td>
|
||||
<td>2011/07/25</td>
|
||||
<td>$170,750</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ashton Cox</td>
|
||||
<td>Junior Technical Author</td>
|
||||
<td>San Francisco</td>
|
||||
<td>66</td>
|
||||
<td>2009/01/12</td>
|
||||
<td>$86,000</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Cedric Kelly</td>
|
||||
<td>Senior Javascript Developer</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>22</td>
|
||||
<td>2012/03/29</td>
|
||||
<td>$433,060</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Airi Satou</td>
|
||||
<td>Accountant</td>
|
||||
<td>Tokyo</td>
|
||||
<td>33</td>
|
||||
<td>2008/11/28</td>
|
||||
<td>$162,700</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Brielle Williamson</td>
|
||||
<td>Integration Specialist</td>
|
||||
<td>New York</td>
|
||||
<td>61</td>
|
||||
<td>2012/12/02</td>
|
||||
<td>$372,000</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Herrod Chandler</td>
|
||||
<td>Sales Assistant</td>
|
||||
<td>San Francisco</td>
|
||||
<td>59</td>
|
||||
<td>2012/08/06</td>
|
||||
<td>$137,500</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Rhona Davidson</td>
|
||||
<td>Integration Specialist</td>
|
||||
<td>Tokyo</td>
|
||||
<td>55</td>
|
||||
<td>2010/10/14</td>
|
||||
<td>$327,900</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Colleen Hurst</td>
|
||||
<td>Javascript Developer</td>
|
||||
<td>San Francisco</td>
|
||||
<td>39</td>
|
||||
<td>2009/09/15</td>
|
||||
<td>$205,500</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sonya Frost</td>
|
||||
<td>Software Engineer</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>23</td>
|
||||
<td>2008/12/13</td>
|
||||
<td>$103,600</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Jena Gaines</td>
|
||||
<td>Office Manager</td>
|
||||
<td>London</td>
|
||||
<td>30</td>
|
||||
<td>2008/12/19</td>
|
||||
<td>$90,560</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Quinn Flynn</td>
|
||||
<td>Support Lead</td>
|
||||
<td>Edinburgh</td>
|
||||
<td>22</td>
|
||||
<td>2013/03/03</td>
|
||||
<td>$342,000</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Charde Marshall</td>
|
||||
<td>Regional Director</td>
|
||||
<td>San Francisco</td>
|
||||
<td>36</td>
|
||||
<td>2008/10/16</td>
|
||||
<td>$470,600</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Haley Kennedy</td>
|
||||
<td>Senior Marketing Designer</td>
|
||||
<td>London</td>
|
||||
<td>43</td>
|
||||
<td>2012/12/18</td>
|
||||
<td>$313,500</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tatyana Fitzpatrick</td>
|
||||
<td>Regional Director</td>
|
||||
<td>London</td>
|
||||
<td>19</td>
|
||||
<td>2010/03/17</td>
|
||||
<td>$385,750</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Michael Silva</td>
|
||||
<td>Marketing Designer</td>
|
||||
<td>London</td>
|
||||
<td>66</td>
|
||||
<td>2012/11/27</td>
|
||||
<td>$198,500</td>
|
||||
</tr>
|
||||
|
||||
</tbody>
|
||||
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -26,15 +26,15 @@ const ProfileImage = memo(({intialData}) => {
|
||||
|
||||
const uploadProfileMutation = useMutation({
|
||||
mutationFn: (fields) => {
|
||||
if(!fields.img){
|
||||
if(!fields.file){
|
||||
throw new Error('Please, select an image')
|
||||
}
|
||||
return uploadProfileImg(fields)
|
||||
},
|
||||
onSuccess: (res) => {
|
||||
if(res.data.resultCode != '0'){
|
||||
throw({message: res?.data?.resultDescription ? res?.data?.resultDescription : 'An error occured'})
|
||||
}
|
||||
// if(res.data.resultCode != '0'){
|
||||
// throw({message: res?.data?.resultDescription ? res?.data?.resultDescription : 'An error occured'})
|
||||
// }
|
||||
// const account_name = res?.data?.personal_data?.account_name
|
||||
// dispatch(updateUserDetails({ account_name }));
|
||||
},
|
||||
@@ -51,8 +51,8 @@ const ProfileImage = memo(({intialData}) => {
|
||||
const proceedToUpload = () => {
|
||||
let reqData = {
|
||||
token: localStorage.getItem('token'), // USER TOKEN
|
||||
uid: localStorage.getItem('uid'), // USER UID
|
||||
img: selectedImg
|
||||
member_uid: localStorage.getItem('uid'), // USER UID
|
||||
file: selectedImg
|
||||
}
|
||||
// console.log('reqData', reqData)
|
||||
uploadProfileMutation.mutate(reqData)
|
||||
|
||||
@@ -57,7 +57,7 @@ export default function Subscription() {
|
||||
<h2 className="text-primary pt-3">{currentSubscription?.display_name}</h2>
|
||||
</div>
|
||||
<div className="pt-2" style={{textAlign: 'left'}}>
|
||||
<div style={{fontSize: '12px', fontWeight: 'bolder' , color: "#3E3699" }}>
|
||||
<div style={{fontSize: '12px', fontWeight: 'bolder', color: "#3E3699"}}>
|
||||
Next Payment: {getDateTimeFromDateString(currentSubscription?.next_payment)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
function sortArrayByListOrder(data) {
|
||||
// Convert object to array if needed
|
||||
const array = Array.isArray(data)
|
||||
? [...data]
|
||||
: Object.values(data);
|
||||
|
||||
// Sort ascending by list_order
|
||||
array.sort((a, b) => {
|
||||
const orderA = a.list_order ?? 0;
|
||||
const orderB = b.list_order ?? 0;
|
||||
return orderA - orderB;
|
||||
});
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
export default sortArrayByListOrder
|
||||
@@ -11,6 +11,7 @@ const siteLinks = {
|
||||
comments: '/comments',
|
||||
reports: '/reports',
|
||||
subscription: '/subscription',
|
||||
my_media: '/my-files',
|
||||
subscription_success:'/subscription-success',
|
||||
subscribe: '/subscribe',
|
||||
onboard: '/subscription',
|
||||
|
||||
@@ -8,9 +8,15 @@ const queryKeys = {
|
||||
recentAction: ['recent-action'],
|
||||
settingsData: ['settings_data'],
|
||||
myProductConfig: ['myproduct_config'],
|
||||
myTemplateConfig: ['mytemplate_config'],
|
||||
productTemplateData: ['product_template_data'],
|
||||
subscriptions: ['subscriptions'],
|
||||
profile_data: ['profile_data'],
|
||||
my_files: ['my_files'],
|
||||
topics: ['topics'],
|
||||
payment_report: ['payment_report'],
|
||||
product_report: ['product_report'],
|
||||
system_report: ['system_report'],
|
||||
|
||||
dashboard: ['dashboard'],
|
||||
topBar: ['top-bar'],
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import axios from "axios"
|
||||
|
||||
|
||||
axios.interceptors.request.use(
|
||||
config => {
|
||||
config.headers = {
|
||||
Accept: "application/json",
|
||||
// Accept: "application/json",
|
||||
"Access-Control-Allow-Origin": "*",
|
||||
// "Access-Control-Expose-Headers": "Access-Control-Allow-Origin",
|
||||
// "Access-Control-Allow-Headers": "Origin, X-API-KEY, X-Requested-With, Content-Type, Accept, Access-Control-Request-Method, Access-Control-Allow-Headers, Authorization, observe, enctype, Content-Length, X-Csrf-Token",
|
||||
@@ -245,6 +244,14 @@ export const getProductColorStyles = (reqData) => {
|
||||
}
|
||||
return postAuxEnd(`/panel/account/products/color-styles`, postData, false)
|
||||
}
|
||||
|
||||
export const getTemplateConfig = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
return postAuxEnd(`/panel/myproduct/template-config`, postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO ACTIVATE TEMPLATE
|
||||
export const activateTemplate = (reqData) => {
|
||||
let postData = {
|
||||
@@ -277,6 +284,59 @@ export const getSubscriptions = (reqData) => {
|
||||
return postAuxEnd(`/panel/subscription/products`, postData, false)
|
||||
}
|
||||
|
||||
export const getMediaFileList = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
return postAuxEnd(`/panel/account/media-files`, postData, false)
|
||||
}
|
||||
|
||||
export const uploadFile = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
return postAuxEnd(`/upload/webfiles`, postData, true)
|
||||
}
|
||||
|
||||
// FUNCTION TO CHANGE TEMPLATE MEDIA SET
|
||||
export const templateMediaSet = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
return postAuxEnd(`/panel/myproduct/template-media-set`, postData, false)
|
||||
}
|
||||
|
||||
export const getReportsTopicsList = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
return postAuxEnd(`/panel/report/topics`, postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO GET PAYMENT REPORTS
|
||||
export const getPaymentReports = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
return postAuxEnd(`/panel/report/item/payment`, postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO GET PRODUCT REPORTS
|
||||
export const getProductReports = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
return postAuxEnd(`/panel/report/item/product`, postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO GET SYSTEM REPORTS
|
||||
export const getSystemReports = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
return postAuxEnd(`/panel/report/item/system`, postData, false)
|
||||
}
|
||||
|
||||
// FUNCTION TO GET COMMON PRACTICE
|
||||
export const getCommonPractice = (reqData) => {
|
||||
let postData = {
|
||||
@@ -298,8 +358,8 @@ export const uploadProfileImg = (reqData) => {
|
||||
let postData = {
|
||||
...reqData,
|
||||
}
|
||||
throw new Error('Opps')
|
||||
// return postAuxEnd(`/panel/account/profile-update`, postData, true)
|
||||
return postAuxEnd(`/upload/profile-picture`, postData, true)
|
||||
// throw new Error('Opps')
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import React from 'react'
|
||||
import MyMedia from "../component/mymedia/MyMedia";
|
||||
|
||||
export default function MyMediaPage() {
|
||||
return (
|
||||
<MyMedia />
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user