Compare commits
113 Commits
refresh-msg
...
bug-fix
| Author | SHA1 | Date | |
|---|---|---|---|
| ef24f269dc | |||
| 51df8293c3 | |||
| 546b6177dc | |||
| db116f36e3 | |||
| 4f93c5b2c2 | |||
| 0a3ca0234e | |||
| a88da5cf0e | |||
| 159f1fcdc8 | |||
| f50df99417 | |||
| 9217e88831 | |||
| 49c6c6afe9 | |||
| ffd00155e0 | |||
| 9fd3636ffd | |||
| 5ff6b4a4d2 | |||
| 22c431c8e0 | |||
| 2db3a4d6f4 | |||
| 1310561e55 | |||
| edcb6cac7d | |||
| be8460c20b | |||
| 0794dfb8e0 | |||
| d950988e62 | |||
| 295473d416 | |||
| acc2c6eab4 | |||
| 9f6db5d13d | |||
| 71e66d3783 | |||
| 2c7085b04b | |||
| 2c7584c00f | |||
| 4d00178d94 | |||
| 863da32f93 | |||
| b9ad9e922e | |||
| 5ad75e412b | |||
| e9d6689418 | |||
| ed38e0db98 | |||
| 351f027a6f | |||
| 20d56ee307 | |||
| f5c798c6c1 | |||
| a11f5100ba | |||
| 7628a561f8 | |||
| 615acff0b7 | |||
| aea161ccaf | |||
| 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 | |||
| 325d28c1a8 | |||
| 25269a44c3 | |||
| 47df35d076 | |||
| 1deb15029d | |||
| 30b284064d | |||
| 4cbe78efc3 | |||
| 92ac7d74f4 | |||
| f0382cea9e | |||
| 2123af0abe | |||
| a3c306bf89 | |||
| a61abe718a | |||
| 2b91506c61 | |||
| 253cace3fe | |||
| aa55a1a4e0 | |||
| 8b763882fa | |||
| 30540e46ba | |||
| b195b1f787 | |||
| 2ddd04a1a1 | |||
| 6ea26740a4 | |||
| f334ca49f0 | |||
| fa9d7f69e4 | |||
| a4db58ba97 | |||
| ddc747d9ca | |||
| ac337eb693 | |||
| f2c3415b1d | |||
| 37450925e1 | |||
| 3b20fcec68 | |||
| d87a083c3e | |||
| 3f8a7a6b3b | |||
| 91d82db40c | |||
| 2dc12d7d0a | |||
| 164195d4cc |
@@ -16,3 +16,14 @@ REACT_APP_TERMS_LINK='https://qa-www.mermsemr.com/terms'
|
|||||||
# Inactivity timeout/logout AT 10MINS
|
# Inactivity timeout/logout AT 10MINS
|
||||||
REACT_APP_TIMEOUT=600000
|
REACT_APP_TIMEOUT=600000
|
||||||
|
|
||||||
|
# show download button
|
||||||
|
REACT_APP_SHOW_DOWNLOAD=0
|
||||||
|
|
||||||
|
REACT_APP_DNS1='dns1.mermsemr.net'
|
||||||
|
REACT_APP_DNS2='dns1.mermsemr.net'
|
||||||
|
REACT_APP_DNS_LINK='https://qa-www.mermsemr.com/info/dns'
|
||||||
|
|
||||||
|
|
||||||
|
#CLOUDFLARE
|
||||||
|
REACT_APP_TURNSTILE_SITE_KEY=0x4AAAAAADQV82wuocFR-u5O
|
||||||
|
|
||||||
|
|||||||
@@ -17,3 +17,13 @@ REACT_APP_TERMS_LINK='https://qa-www.mermsemr.com/terms'
|
|||||||
# Inactivity timeout/logout AT 10MINS
|
# Inactivity timeout/logout AT 10MINS
|
||||||
REACT_APP_TIMEOUT=600000
|
REACT_APP_TIMEOUT=600000
|
||||||
|
|
||||||
|
# show download button
|
||||||
|
REACT_APP_SHOW_DOWNLOAD=0
|
||||||
|
|
||||||
|
REACT_APP_DNS1='dns1.mermsemr.net'
|
||||||
|
REACT_APP_DNS2='dns1.mermsemr.net'
|
||||||
|
REACT_APP_DNS_LINK='https://qa-www.mermsemr.com/info/dns'
|
||||||
|
|
||||||
|
#CLOUDFLARE
|
||||||
|
REACT_APP_TURNSTILE_SITE_KEY=0x4AAAAAADQV82wuocFR-u5O
|
||||||
|
|
||||||
|
|||||||
@@ -15,3 +15,14 @@ REACT_APP_TERMS_LINK='https://www.mermsemr.com/terms'
|
|||||||
|
|
||||||
# Inactivity timeout/logout AT 10MINS
|
# Inactivity timeout/logout AT 10MINS
|
||||||
REACT_APP_TIMEOUT=600000
|
REACT_APP_TIMEOUT=600000
|
||||||
|
|
||||||
|
# show download button
|
||||||
|
REACT_APP_SHOW_DOWNLOAD=0
|
||||||
|
|
||||||
|
REACT_APP_DNS1='dns1.mermsemr.net'
|
||||||
|
REACT_APP_DNS2='dns1.mermsemr.net'
|
||||||
|
REACT_APP_DNS_LINK='https://www.mermsemr.com/info/dns'
|
||||||
|
|
||||||
|
#CLOUDFLARE
|
||||||
|
REACT_APP_TURNSTILE_SITE_KEY=0x4AAAAAADQV82wuocFR-u5O
|
||||||
|
|
||||||
|
|||||||
@@ -15,3 +15,11 @@ REACT_APP_TERMS_LINK='https://qa-www.mermsemr.com/terms'
|
|||||||
|
|
||||||
# Inactivity timeout/logout AT 10MINS
|
# Inactivity timeout/logout AT 10MINS
|
||||||
REACT_APP_TIMEOUT=600000
|
REACT_APP_TIMEOUT=600000
|
||||||
|
|
||||||
|
REACT_APP_DNS1='dns1.mermsemr.net'
|
||||||
|
REACT_APP_DNS2='dns1.mermsemr.net'
|
||||||
|
REACT_APP_DNS_LINK='https://qa-www.mermsemr.com/info/dns'
|
||||||
|
|
||||||
|
#CLOUDFLARE
|
||||||
|
REACT_APP_TURNSTILE_SITE_KEY=0x4AAAAAADQV82wuocFR-u5O
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -1,12 +1,12 @@
|
|||||||
version: '3'
|
version: '3'
|
||||||
services:
|
services:
|
||||||
merms-panel:
|
merms-panel:
|
||||||
image: registry.chiefsoft.net/merms-panel-reactjs:latest
|
# image: registry.chiefsoft.net/merms-panel-reactjs:latest
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: docker/Dockerfile
|
dockerfile: docker/Dockerfile
|
||||||
args:
|
# args:
|
||||||
- NODE_ENV=development
|
# - NODE_ENV=development
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- 8090:3000
|
- 8090:3000
|
||||||
|
|||||||
+22
-22
@@ -1,12 +1,12 @@
|
|||||||
# pull the base image
|
# pull the base image
|
||||||
# FROM node:alpine
|
# FROM node:alpine
|
||||||
|
|
||||||
FROM alpine:3.15
|
FROM alpine:3.22
|
||||||
|
|
||||||
# Build args
|
# Build args
|
||||||
ARG NODE_ENV
|
ARG NODE_ENV
|
||||||
|
|
||||||
ENV NODE_VERSION 14.19.0
|
ENV NODE_VERSION=14.19.0
|
||||||
ENV NODE_ENV=$NODE_ENV
|
ENV NODE_ENV=$NODE_ENV
|
||||||
|
|
||||||
# install nginx
|
# install nginx
|
||||||
@@ -82,26 +82,26 @@ RUN addgroup -g 1000 node \
|
|||||||
&& node --version \
|
&& node --version \
|
||||||
&& npm --version
|
&& npm --version
|
||||||
|
|
||||||
ENV YARN_VERSION 1.22.17
|
# ENV YARN_VERSION 1.22.17
|
||||||
|
|
||||||
RUN apk add --no-cache --virtual .build-deps-yarn curl gnupg tar \
|
# RUN apk add --no-cache --virtual .build-deps-yarn curl gnupg tar \
|
||||||
&& for key in \
|
# && for key in \
|
||||||
6A010C5166006599AA17F08146C2130DFD2497F5 \
|
# 6A010C5166006599AA17F08146C2130DFD2497F5 \
|
||||||
; do \
|
# ; do \
|
||||||
gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" || \
|
# gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys "$key" || \
|
||||||
gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \
|
# gpg --batch --keyserver keyserver.ubuntu.com --recv-keys "$key" ; \
|
||||||
done \
|
# done \
|
||||||
&& curl -fsSLO --compressed "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \
|
# && curl -fsSLO --compressed "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" \
|
||||||
&& curl -fsSLO --compressed "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz.asc" \
|
# && curl -fsSLO --compressed "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz.asc" \
|
||||||
&& gpg --batch --verify yarn-v$YARN_VERSION.tar.gz.asc yarn-v$YARN_VERSION.tar.gz \
|
# && gpg --batch --verify yarn-v$YARN_VERSION.tar.gz.asc yarn-v$YARN_VERSION.tar.gz \
|
||||||
&& mkdir -p /opt \
|
# && mkdir -p /opt \
|
||||||
&& tar -xzf yarn-v$YARN_VERSION.tar.gz -C /opt/ \
|
# && tar -xzf yarn-v$YARN_VERSION.tar.gz -C /opt/ \
|
||||||
&& ln -s /opt/yarn-v$YARN_VERSION/bin/yarn /usr/local/bin/yarn \
|
# && ln -s /opt/yarn-v$YARN_VERSION/bin/yarn /usr/local/bin/yarn \
|
||||||
&& ln -s /opt/yarn-v$YARN_VERSION/bin/yarnpkg /usr/local/bin/yarnpkg \
|
# && ln -s /opt/yarn-v$YARN_VERSION/bin/yarnpkg /usr/local/bin/yarnpkg \
|
||||||
&& rm yarn-v$YARN_VERSION.tar.gz.asc yarn-v$YARN_VERSION.tar.gz \
|
# && rm yarn-v$YARN_VERSION.tar.gz.asc yarn-v$YARN_VERSION.tar.gz \
|
||||||
&& apk del .build-deps-yarn \
|
# && apk del .build-deps-yarn \
|
||||||
# smoke test
|
# # smoke test
|
||||||
&& yarn --version
|
# && yarn --version
|
||||||
|
|
||||||
# set working directory
|
# set working directory
|
||||||
# WORKDIR /app
|
# WORKDIR /app
|
||||||
@@ -109,7 +109,7 @@ RUN apk add --no-cache --virtual .build-deps-yarn curl gnupg tar \
|
|||||||
|
|
||||||
# add `/app/node_modules/.bin` to $PATH
|
# add `/app/node_modules/.bin` to $PATH
|
||||||
# ENV PATH /app/node_modules/.bin:$PATH
|
# ENV PATH /app/node_modules/.bin:$PATH
|
||||||
ENV PATH /usr/src/app/node_modules/.bin:$PATH
|
ENV PATH=/usr/src/app/node_modules/.bin:$PATH
|
||||||
|
|
||||||
COPY nginx.conf ./
|
COPY nginx.conf ./
|
||||||
|
|
||||||
|
|||||||
Generated
+10181
-3715
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@
|
|||||||
"@fullcalendar/interaction": "^6.1.15",
|
"@fullcalendar/interaction": "^6.1.15",
|
||||||
"@fullcalendar/react": "^6.1.15",
|
"@fullcalendar/react": "^6.1.15",
|
||||||
"@fullcalendar/timegrid": "^6.1.15",
|
"@fullcalendar/timegrid": "^6.1.15",
|
||||||
|
"@marsidev/react-turnstile": "^1.5.2",
|
||||||
"@popperjs/core": "^2.11.8",
|
"@popperjs/core": "^2.11.8",
|
||||||
"@reduxjs/toolkit": "^2.4.0",
|
"@reduxjs/toolkit": "^2.4.0",
|
||||||
"@stripe/react-stripe-js": "^3.9.1",
|
"@stripe/react-stripe-js": "^3.9.1",
|
||||||
|
|||||||
@@ -52,3 +52,10 @@ button{
|
|||||||
.accordion-button, .accordion-button:not(.collapsed) {
|
.accordion-button, .accordion-button:not(.collapsed) {
|
||||||
background-color: transparent!important;
|
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 SubscribePage from './views/Subscribe'
|
||||||
import StartPage from "./views/StartPage";
|
import StartPage from "./views/StartPage";
|
||||||
import TrafficPage from "./views/TrafficPage";
|
import TrafficPage from "./views/TrafficPage";
|
||||||
|
import MyMediaPage from './views/MyMediaPage.jsx';
|
||||||
|
|
||||||
function AppRouters() {
|
function AppRouters() {
|
||||||
return (
|
return (
|
||||||
@@ -52,6 +53,7 @@ function AppRouters() {
|
|||||||
<Route path={siteLinks.profile_complete} element={<ProfileCompletePage/>}/>
|
<Route path={siteLinks.profile_complete} element={<ProfileCompletePage/>}/>
|
||||||
<Route path={siteLinks.product} element={<ProductPage/>}/>
|
<Route path={siteLinks.product} element={<ProductPage/>}/>
|
||||||
<Route path={siteLinks.reports} element={<ReportsPage/>}/>
|
<Route path={siteLinks.reports} element={<ReportsPage/>}/>
|
||||||
|
<Route path={siteLinks.my_media} element={<MyMediaPage />}/>
|
||||||
<Route path={siteLinks.comments} element={<CommentsPage/>}/>
|
<Route path={siteLinks.comments} element={<CommentsPage/>}/>
|
||||||
<Route path={siteLinks.contacts} element={<ContactsPage/>}/>
|
<Route path={siteLinks.contacts} element={<ContactsPage/>}/>
|
||||||
<Route path={siteLinks.user} element={<UserPage/>}/>
|
<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 |
Binary file not shown.
|
After Width: | Height: | Size: 78 KiB |
@@ -0,0 +1,42 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import GoogleDownload from '../../assets/img/download/andriod.jpg'
|
||||||
|
import IOSDownload from '../../assets/img/download/apple.jpg'
|
||||||
|
|
||||||
|
export default function AuthFooter() {
|
||||||
|
return (
|
||||||
|
<div className='w-100'>
|
||||||
|
{Number(process.env.REACT_APP_SHOW_DOWNLOAD) == 100 &&
|
||||||
|
<>
|
||||||
|
<div className="row" style={{margin: '5px'}}>
|
||||||
|
<hr />
|
||||||
|
</div>
|
||||||
|
<div className="row" style={{marginTop: '20px'}}>
|
||||||
|
<div className="col-6">
|
||||||
|
<div className="app-store-icons-wrap text-center">
|
||||||
|
<a className="icon google"
|
||||||
|
href='#' >
|
||||||
|
<img src={IOSDownload} className='w-80 h-auto' alt='IOS Download' />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="col-6">
|
||||||
|
<div className="app-store-icons-wrap text-center">
|
||||||
|
<a className="icon apple" href='#'>
|
||||||
|
<img src={GoogleDownload} className='w-80 h-auto' alt='IOS Download' />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
<div className="login-links">
|
||||||
|
<a href={process.env.REACT_APP_HOME_LINK}>Home</a>
|
||||||
|
<a href={process.env.REACT_APP_ABOUT_LINK}>About</a>
|
||||||
|
<a href={process.env.REACT_APP_CONTACTS_LINK}>Contact</a>
|
||||||
|
<a href={process.env.REACT_APP_TERMS_LINK}>Terms</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -56,7 +56,7 @@ export default function CSignup() {
|
|||||||
},
|
},
|
||||||
onSuccess: (res) => {
|
onSuccess: (res) => {
|
||||||
if(res?.data?.resultCode != '0'){
|
if(res?.data?.resultCode != '0'){
|
||||||
throw({message: res?.data?.resultDescription})
|
throw({message: res?.data?.error_message})
|
||||||
}
|
}
|
||||||
const {token, room, uid} = res?.data
|
const {token, room, uid} = res?.data
|
||||||
if(!token || !room){
|
if(!token || !room){
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { Form, Formik } from "formik";
|
import { Form, Formik } from "formik";
|
||||||
|
import { Turnstile } from '@marsidev/react-turnstile'
|
||||||
import * as Yup from "yup";
|
import * as Yup from "yup";
|
||||||
// import LoginImg from '../../assets/bg/login.svg'
|
// import LoginImg from '../../assets/bg/login.svg'
|
||||||
|
|
||||||
@@ -8,6 +9,7 @@ import siteLinks from '../../links/siteLinks'
|
|||||||
import { useMutation } from '@tanstack/react-query'
|
import { useMutation } from '@tanstack/react-query'
|
||||||
import { recoverPWD } from '../../services/services';
|
import { recoverPWD } from '../../services/services';
|
||||||
import getImage from '../../utils/getImage';
|
import getImage from '../../utils/getImage';
|
||||||
|
import AuthFooter from './AuthFooter';
|
||||||
|
|
||||||
const validationSchema = Yup.object().shape({
|
const validationSchema = Yup.object().shape({
|
||||||
username: Yup.string()
|
username: Yup.string()
|
||||||
@@ -16,13 +18,14 @@ const validationSchema = Yup.object().shape({
|
|||||||
// /^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/,
|
// /^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/,
|
||||||
// "Invalid email format"
|
// "Invalid email format"
|
||||||
// )
|
// )
|
||||||
.min(3, "Minimum 3 characters")
|
.min(3, "Username must be at least 3 characters")
|
||||||
.max(50, "Maximum 50 characters")
|
.max(25, "Entered Username is too long")
|
||||||
.required("Email is required"),
|
.required("Enter a valid username to continue"),
|
||||||
})
|
})
|
||||||
|
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
username: ''
|
username: '',
|
||||||
|
turnstileToken: ''
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function Forgetpwd2() {
|
export default function Forgetpwd2() {
|
||||||
@@ -49,7 +52,7 @@ export default function Forgetpwd2() {
|
|||||||
<div className="row no-gutters justify-content-center">
|
<div className="row no-gutters justify-content-center">
|
||||||
<div className="col-11 col-sm-6 col-lg-5 col-xxl-4 align-self-center order-2 order-sm-1h" style={{maxWidth: '520px'}}>
|
<div className="col-11 col-sm-6 col-lg-5 col-xxl-4 align-self-center order-2 order-sm-1h" style={{maxWidth: '520px'}}>
|
||||||
<div className="mt-5 d-flex">
|
<div className="mt-5 d-flex">
|
||||||
<div className="bg-white register p-5">
|
<div className="bg-white register px-5 pt-5 pb-3">
|
||||||
<h1 className="mb-2">{process.env.REACT_APP_PANEL_NAME}</h1>
|
<h1 className="mb-2">{process.env.REACT_APP_PANEL_NAME}</h1>
|
||||||
{!mutation.isSuccess && <p>Please enter your username.</p>}
|
{!mutation.isSuccess && <p>Please enter your username.</p>}
|
||||||
<Formik
|
<Formik
|
||||||
@@ -65,7 +68,7 @@ export default function Forgetpwd2() {
|
|||||||
<>
|
<>
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label className={`text-black fw-bold control-label ${(props.errors.username && props.touched.username) && 'text-danger'}`}>Username*</label>
|
<label className={`text-black fw-bold control-label`}>Username* <span className='text-danger' style={{fontSize: '12px'}}>{(props.errors.username && props.touched.username) && props.errors.username}</span></label>
|
||||||
<input type="text" name='username' className="form-control" placeholder="Username" value={props.values.username} onChange={props.handleChange} />
|
<input type="text" name='username' className="form-control" placeholder="Username" value={props.values.username} onChange={props.handleChange} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -76,8 +79,18 @@ export default function Forgetpwd2() {
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<div className="text-center col-12 mt-3">
|
||||||
|
<Turnstile
|
||||||
|
siteKey={process.env.REACT_APP_TURNSTILE_SITE_KEY}
|
||||||
|
onSuccess={(token) => props.setFieldValue('turnstileToken', token)}
|
||||||
|
onExpire={() => props.setFieldValue('turnstileToken', null)}
|
||||||
|
onError={() => props.setFieldValue('turnstileToken', null)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="col-12 mt-3 text-end">
|
<div className="col-12 mt-3 text-end">
|
||||||
<button type='submit' className="btn btn-primary text-uppercase">{mutation.isPending ? 'loading...' : 'Send'}</button>
|
<button type='submit' disabled={!props.values.turnstileToken || mutation.isPending} className="btn btn-primary text-uppercase">{mutation.isPending ? 'loading...' : 'Send'}</button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
:
|
:
|
||||||
@@ -97,6 +110,7 @@ export default function Forgetpwd2() {
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</Formik>
|
</Formik>
|
||||||
|
<AuthFooter />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { useMutation } from '@tanstack/react-query'
|
import { useMutation } from '@tanstack/react-query'
|
||||||
import { useDispatch, useSelector } from 'react-redux'
|
import { useDispatch, useSelector } from 'react-redux'
|
||||||
|
import { Turnstile } from '@marsidev/react-turnstile'
|
||||||
|
|
||||||
// import LoginImg from '../../assets/bg/login.svg'
|
// import LoginImg from '../../assets/bg/login.svg'
|
||||||
|
|
||||||
@@ -9,8 +10,7 @@ import siteLinks from '../../links/siteLinks'
|
|||||||
import { loginUser } from '../../services/services'
|
import { loginUser } from '../../services/services'
|
||||||
import { updateUserDetails } from '../../store/UserDetails'
|
import { updateUserDetails } from '../../store/UserDetails'
|
||||||
|
|
||||||
import GoogleDownload from '../../assets/img/download/andriod.jpg'
|
import AuthFooter from './AuthFooter'
|
||||||
import IOSDownload from '../../assets/img/download/apple.jpg'
|
|
||||||
|
|
||||||
export default function Login() {
|
export default function Login() {
|
||||||
|
|
||||||
@@ -27,6 +27,8 @@ export default function Login() {
|
|||||||
remember: false
|
remember: false
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const [turnstileToken, setTurnstileToken] = useState(null)
|
||||||
|
|
||||||
const handleChange = ({target:{name, value}}) => {
|
const handleChange = ({target:{name, value}}) => {
|
||||||
if(name == 'remember'){
|
if(name == 'remember'){
|
||||||
return setFields(prev => ({...prev, remember:!prev.remember}))
|
return setFields(prev => ({...prev, remember:!prev.remember}))
|
||||||
@@ -35,24 +37,24 @@ export default function Login() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const login = useMutation({
|
const login = useMutation({
|
||||||
mutationFn: (fields) => {
|
mutationFn: ({ turnstileToken, ...fields }) => {
|
||||||
if(!fields.username || !fields.password){
|
if(!fields.username || !fields.password){
|
||||||
throw new Error('Please provide all fields marked *')
|
throw new Error('Please provide all fields marked *')
|
||||||
}
|
}
|
||||||
rememberMe(fields.remember) // FUNCTION TO SAVE USERNAME OF THE USER TO LOCAL STORAGE
|
rememberMe(fields.remember)
|
||||||
delete fields.remember // REMOVING REMEMBER FROM THE PAYLOAD
|
delete fields.remember
|
||||||
return loginUser(fields)
|
return loginUser({ ...fields, turnstileToken })
|
||||||
},
|
},
|
||||||
onError: (error) => {
|
onError: (error) => {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
},
|
},
|
||||||
onSuccess: (res) => {
|
onSuccess: (res) => {
|
||||||
if(res?.data?.error_message){
|
if(res?.data && res?.data?.error_message){
|
||||||
throw({message: res?.data?.error_message})
|
throw({message: res?.data?.error_message})
|
||||||
}
|
}
|
||||||
const {token, room, uid} = res?.data
|
const {token, room, uid} = res?.data
|
||||||
if(!token || !room){
|
if(!token || !room){
|
||||||
throw({message: 'something went wrong, try again!'})
|
throw({message: 'Unable to complete your login, Please try again!'})
|
||||||
}
|
}
|
||||||
localStorage.setItem('token', token)
|
localStorage.setItem('token', token)
|
||||||
localStorage.setItem('room', room)
|
localStorage.setItem('room', room)
|
||||||
@@ -70,7 +72,7 @@ export default function Login() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(()=>{ // NAVIGATES USER TO HOME PAGE IF USER IS ACTIVE
|
useEffect(()=>{ // NAVIGATES USER TO HOME PAGE IF USER IS CURRENTLY ACTIVE
|
||||||
if(loggedIn){
|
if(loggedIn){
|
||||||
navigate(siteLinks.dash)
|
navigate(siteLinks.dash)
|
||||||
}
|
}
|
||||||
@@ -102,6 +104,14 @@ export default function Login() {
|
|||||||
<input maxLength={25} name='password' value={fields.password} onChange={handleChange} type="password" className="form-control" placeholder="Password" />
|
<input maxLength={25} name='password' value={fields.password} onChange={handleChange} type="password" className="form-control" placeholder="Password" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="text-center col-12 mt-3">
|
||||||
|
<Turnstile
|
||||||
|
siteKey={process.env.REACT_APP_TURNSTILE_SITE_KEY}
|
||||||
|
onSuccess={setTurnstileToken}
|
||||||
|
onExpire={() => setTurnstileToken(null)}
|
||||||
|
onError={() => setTurnstileToken(null)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<div className="d-block d-sm-flex align-items-center">
|
<div className="d-block d-sm-flex align-items-center">
|
||||||
<div className="form-check">
|
<div className="form-check">
|
||||||
@@ -121,47 +131,19 @@ export default function Login() {
|
|||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
<div className="col-12 mt-3 text-end">
|
<div className="col-12 mt-3 text-end">
|
||||||
<button type='button' onClick={()=>{login.mutate(fields)}} className="btn btn-primary text-uppercase">{login.isPending ? 'loading...' : 'Sign In'}</button>
|
<button type='button' onClick={()=>{login.mutate({...fields, turnstileToken})}} disabled={!turnstileToken || login.isPending} className="btn btn-primary text-uppercase">{login.isPending ? 'loading...' : 'Sign In'}</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-12 mt-3">
|
<div className="col-12 mt-3">
|
||||||
<p> <Link to={siteLinks.signup}>
|
<p> <Link to={siteLinks.signup}>
|
||||||
{/*<span style={{fontWeight: 'bolder'}}>Sign Up</span>*/}
|
{/*<span style={{fontWeight: 'bolder'}}>Sign Up</span>*/}
|
||||||
<button className="btn btn-warning text-uppercase">
|
<button type='button' className="btn btn-warning text-uppercase">
|
||||||
Sign Up
|
Sign Up
|
||||||
</button>
|
</button>
|
||||||
</Link><span style={{paddingLeft: '5px' , fontWeight: 'bolder'}}> if you don't have an account yet.</span></p>
|
</Link><span style={{paddingLeft: '5px' , fontWeight: 'bolder'}}> if you don't have an account yet.</span></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div className="row" style={{margin: '5px'}}>
|
<AuthFooter />
|
||||||
<hr />
|
|
||||||
</div>
|
|
||||||
<div className="row" style={{marginTop: '20px'}}>
|
|
||||||
<div className="col-6">
|
|
||||||
<div className="app-store-icons-wrap text-center">
|
|
||||||
<a className="icon google"
|
|
||||||
href='#' >
|
|
||||||
<img src={IOSDownload} className='w-80 h-auto' alt='IOS Download' />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="col-6">
|
|
||||||
<div className="app-store-icons-wrap text-center">
|
|
||||||
<a className="icon apple" href='#'>
|
|
||||||
<img src={GoogleDownload} className='w-80 h-auto' alt='IOS Download' />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="login-links">
|
|
||||||
<a href={process.env.REACT_APP_HOME_LINK}>Home</a>
|
|
||||||
<a href={process.env.REACT_APP_ABOUT_LINK}>About</a>
|
|
||||||
<a href={process.env.REACT_APP_CONTACTS_LINK}>Contact</a>
|
|
||||||
<a href={process.env.REACT_APP_TERMS_LINK}>Terms</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React, {useState} from 'react'
|
import React, {useState} from 'react'
|
||||||
import {Form, Formik} from "formik";
|
import {Form, Formik} from "formik";
|
||||||
|
import { Turnstile } from '@marsidev/react-turnstile'
|
||||||
import * as Yup from "yup";
|
import * as Yup from "yup";
|
||||||
|
|
||||||
// import LoginImg from '../../assets/bg/login.svg'
|
// import LoginImg from '../../assets/bg/login.svg'
|
||||||
@@ -9,6 +10,7 @@ import siteLinks from '../../links/siteLinks'
|
|||||||
import {useMutation} from '@tanstack/react-query';
|
import {useMutation} from '@tanstack/react-query';
|
||||||
import {signUpUser} from '../../services/services';
|
import {signUpUser} from '../../services/services';
|
||||||
import getImage from '../../utils/getImage';
|
import getImage from '../../utils/getImage';
|
||||||
|
import AuthFooter from './AuthFooter';
|
||||||
|
|
||||||
const validationSchema = Yup.object().shape({
|
const validationSchema = Yup.object().shape({
|
||||||
email: Yup.string()
|
email: Yup.string()
|
||||||
@@ -32,6 +34,7 @@ const initialValues = {
|
|||||||
firstname: '',
|
firstname: '',
|
||||||
lastname: '',
|
lastname: '',
|
||||||
isChecked: false,
|
isChecked: false,
|
||||||
|
turnstileToken: '',
|
||||||
// username: '',
|
// username: '',
|
||||||
// password: ''
|
// password: ''
|
||||||
};
|
};
|
||||||
@@ -64,9 +67,9 @@ export default function Signup2() {
|
|||||||
<div className="col-11 col-sm-6 col-lg-5 col-xxl-4 align-self-center order-2 order-sm-1"
|
<div className="col-11 col-sm-6 col-lg-5 col-xxl-4 align-self-center order-2 order-sm-1"
|
||||||
style={{maxWidth: '520px'}}>
|
style={{maxWidth: '520px'}}>
|
||||||
<div className="mt-5 d-flex">
|
<div className="mt-5 d-flex">
|
||||||
<div className="bg-white register p-5">
|
<div className="bg-white register px-5 pt-5 pb-3">
|
||||||
<h1 className="mb-2">{process.env.REACT_APP_PANEL_NAME}</h1>
|
<h1 className="mb-2">{process.env.REACT_APP_PANEL_NAME}</h1>
|
||||||
<p>Welcome, Please create your account.</p>
|
<p>Welcome, please create your account.</p>
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
validationSchema={validationSchema}
|
validationSchema={validationSchema}
|
||||||
@@ -134,7 +137,15 @@ export default function Signup2() {
|
|||||||
onChange={props.handleChange}/>
|
onChange={props.handleChange}/>
|
||||||
<label className="form-check-label"
|
<label className="form-check-label"
|
||||||
htmlFor="gridCheck">
|
htmlFor="gridCheck">
|
||||||
I accept terms & policy
|
I accept{" "}
|
||||||
|
<a
|
||||||
|
href={process.env.REACT_APP_TERMS_LINK}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
terms & policy
|
||||||
|
</a>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<span
|
<span
|
||||||
@@ -148,9 +159,17 @@ export default function Signup2() {
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
|
<div className="text-center col-12 mt-3">
|
||||||
|
<Turnstile
|
||||||
|
siteKey={process.env.REACT_APP_TURNSTILE_SITE_KEY}
|
||||||
|
onSuccess={(token) => props.setFieldValue('turnstileToken', token)}
|
||||||
|
onExpire={() => props.setFieldValue('turnstileToken', null)}
|
||||||
|
onError={() => props.setFieldValue('turnstileToken', null)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div className="col-12 mt-3 text-end">
|
<div className="col-12 mt-3 text-end">
|
||||||
<button type='submit'
|
<button type='submit'
|
||||||
|
disabled={!props.values.turnstileToken || mutation.isPending}
|
||||||
className="btn btn-primary text-uppercase">{mutation.isPending ? 'loading...' : 'Sign up'}</button>
|
className="btn btn-primary text-uppercase">{mutation.isPending ? 'loading...' : 'Sign up'}</button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
@@ -173,19 +192,23 @@ export default function Signup2() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
<div className="col-12 mt-3">
|
<div className="col-12 mt-3">
|
||||||
<p>Already have an account ?<Link
|
<p>
|
||||||
|
<span style={{paddingLeft: '5px' , fontWeight: 'bolder'}}>Already have an account? </span>
|
||||||
|
<Link
|
||||||
to={siteLinks.login}>
|
to={siteLinks.login}>
|
||||||
<button
|
<button
|
||||||
className="btn btn-warning text-uppercase">
|
className="btn btn-warning text-uppercase">
|
||||||
Sign In
|
Sign In
|
||||||
</button>
|
</button>
|
||||||
</Link></p>
|
</Link>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</Formik>
|
</Formik>
|
||||||
|
<AuthFooter />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -48,7 +48,8 @@ export default function Calendar(){
|
|||||||
}
|
}
|
||||||
const {data, isFetching, isError, error} = useQuery({
|
const {data, isFetching, isError, error} = useQuery({
|
||||||
queryKey: queryKeys.calendar_events,
|
queryKey: queryKeys.calendar_events,
|
||||||
queryFn: () => getCalendarEvents(reqData)
|
queryFn: () => getCalendarEvents(reqData),
|
||||||
|
staleTime: 0
|
||||||
})
|
})
|
||||||
|
|
||||||
const receievedEvents = data?.data
|
const receievedEvents = data?.data
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||||
import getImage from "../../utils/getImage";
|
import getImage from "../../utils/getImage";
|
||||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import { commentsData } from "../../services/services";
|
import { commentsData } from "../../services/services";
|
||||||
import queryKeys from "../../services/queryKeys";
|
// import queryKeys from "../../services/queryKeys";
|
||||||
import getCustomTime from "../../utils/getCustomTime";
|
// import getCustomTime from "../../utils/getCustomTime";
|
||||||
|
|
||||||
export default function Comments() {
|
export default function Comments() {
|
||||||
// const {data:contacts, isFetching, isError, error} = useQuery({
|
// const {data:contacts, isFetching, isError, error} = useQuery({
|
||||||
@@ -197,8 +197,13 @@ export default function Comments() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={`${filteredContactData.length > 0 ? 'col-md-8 col-xxl-4' : 'col-md-8 col-xxl-10'} border-md-t`}>
|
<div
|
||||||
<div className="mail-content border-right border-n h-100" style={{placeContent: 'center'}}>
|
className={`${filteredContactData.length > 0 ? "col-md-8 col-xxl-4" : "col-md-8 col-xxl-10"} border-md-t`}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="mail-content border-right border-n h-100"
|
||||||
|
style={{ placeContent: "center" }}
|
||||||
|
>
|
||||||
{/* <div className="mail-search border-bottom">
|
{/* <div className="mail-search border-bottom">
|
||||||
<div className="row align-items-center mx-0">
|
<div className="row align-items-center mx-0">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
@@ -210,7 +215,7 @@ export default function Comments() {
|
|||||||
</div>
|
</div>
|
||||||
</div> */}
|
</div> */}
|
||||||
<div className="mail-msg scrollbar scroll_dark">
|
<div className="mail-msg scrollbar scroll_dark">
|
||||||
{ filteredContactData.length ?
|
{filteredContactData.length ? (
|
||||||
filteredContactData?.map((contact, index) => {
|
filteredContactData?.map((contact, index) => {
|
||||||
const isActive =
|
const isActive =
|
||||||
contact?.uid == activeContactUID ||
|
contact?.uid == activeContactUID ||
|
||||||
@@ -255,7 +260,7 @@ export default function Comments() {
|
|||||||
<p className="d-none d-xl-block">
|
<p className="d-none d-xl-block">
|
||||||
<span style={{ fontSize: "14px" }}>
|
<span style={{ fontSize: "14px" }}>
|
||||||
{new Date(
|
{new Date(
|
||||||
contact?.added
|
contact?.added,
|
||||||
).toDateString()}
|
).toDateString()}
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
@@ -272,7 +277,7 @@ export default function Comments() {
|
|||||||
<p className="d-xl-none">
|
<p className="d-xl-none">
|
||||||
<span>
|
<span>
|
||||||
{new Date(
|
{new Date(
|
||||||
contact?.added
|
contact?.added,
|
||||||
).toDateString()}
|
).toDateString()}
|
||||||
{/* {getCustomTime(contact.added)} */}
|
{/* {getCustomTime(contact.added)} */}
|
||||||
</span>
|
</span>
|
||||||
@@ -283,19 +288,36 @@ export default function Comments() {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
:
|
) : (
|
||||||
<p className="text-center">Messages will appear here as soon as they are available for selection</p>
|
<p className="text-center">
|
||||||
}
|
Messages will appear here as soon as they are
|
||||||
|
available for selection
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{filteredContactData.length > 0 &&
|
{filteredContactData.length > 0 && (
|
||||||
<div className="col-xxl-6 border-t border-xxl-t">
|
<div className="col-xxl-6 border-t border-xxl-t">
|
||||||
<div className="mail-chat py-5 px-5">
|
<div className="mail-chat py-5 px-5">
|
||||||
<div className="media align-items-center">
|
<div className="media align-items-center">
|
||||||
<div className="bg-img mr-3">
|
<div className="bg-img mr-3">
|
||||||
<img
|
<img
|
||||||
src={activeContactUID ? getImage("avtar/" + activeDetail[0].category + ".png") : getImage(filteredContactData[0] == undefined ? "avtar/01.jpg": "avtar/" + filteredContactData[0].category + ".png")}
|
src={
|
||||||
|
activeContactUID
|
||||||
|
? getImage(
|
||||||
|
"avtar/" +
|
||||||
|
activeDetail[0].category +
|
||||||
|
".png",
|
||||||
|
)
|
||||||
|
: getImage(
|
||||||
|
filteredContactData[0] == undefined
|
||||||
|
? "avtar/01.jpg"
|
||||||
|
: "avtar/" +
|
||||||
|
filteredContactData[0].category +
|
||||||
|
".png",
|
||||||
|
)
|
||||||
|
}
|
||||||
className="img-fluid"
|
className="img-fluid"
|
||||||
alt="user"
|
alt="user"
|
||||||
/>
|
/>
|
||||||
@@ -308,9 +330,11 @@ export default function Comments() {
|
|||||||
</h4>
|
</h4>
|
||||||
<p>
|
<p>
|
||||||
{activeContactUID
|
{activeContactUID
|
||||||
? new Date(activeDetail[0]?.added).toDateString()
|
? new Date(
|
||||||
|
activeDetail[0]?.added,
|
||||||
|
).toDateString()
|
||||||
: new Date(
|
: new Date(
|
||||||
filteredContactData[0]?.added
|
filteredContactData[0]?.added,
|
||||||
).toDateString()}
|
).toDateString()}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -337,7 +361,7 @@ export default function Comments() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -42,19 +42,35 @@ export default function SocketIOContextProvider({children}) {
|
|||||||
// setSocketMsgReceived(data.message);
|
// setSocketMsgReceived(data.message);
|
||||||
// dispatch(tableReload({type:'CHATMESSAGELIST'})) // dispatches to update chat message sending from owner to worker and vice versa
|
// dispatch(tableReload({type:'CHATMESSAGELIST'})) // dispatches to update chat message sending from owner to worker and vice versa
|
||||||
console.log('SOCKET RECEIVED DATA *** ', data)
|
console.log('SOCKET RECEIVED DATA *** ', data)
|
||||||
|
if(data?.message_action === socketOnEvents.refresh_all_actions){
|
||||||
queryClient.refetchQueries({
|
queryClient.refetchQueries({
|
||||||
queryKey: [...queryKeys.recentAction],
|
queryKey: [...queryKeys.recentAction],
|
||||||
// type: 'active',
|
// type: 'active',
|
||||||
// exact: true,
|
// exact: true,
|
||||||
})
|
})
|
||||||
});
|
}
|
||||||
|
if(data?.message_action === socketOnEvents.refresh_provision){
|
||||||
socket.on(socketOnEvents.refresh_provision, (data) => {
|
queryClient.refetchQueries({ // refetches product Page API call
|
||||||
|
queryKey: [...queryKeys.product_page],
|
||||||
|
})
|
||||||
queryClient.refetchQueries({ // refetches productProvision API call
|
queryClient.refetchQueries({ // refetches productProvision API call
|
||||||
queryKey: [...queryKeys.myproduct_provision],
|
queryKey: [...queryKeys.myproduct_provision],
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// socket.on(socketOnEvents.refresh_provision, (data) => {
|
||||||
|
// queryClient.refetchQueries({ // refetches productProvision API call
|
||||||
|
// queryKey: [...queryKeys.myproduct_provision],
|
||||||
|
// })
|
||||||
|
// // queryClient.invalidateQueries({ queryKey: [...queryKeys.product_page] })
|
||||||
|
// queryClient.refetchQueries({ // refetches product Page API call
|
||||||
|
// queryKey: [...queryKeys.product_page],
|
||||||
|
// })
|
||||||
|
// console.log('SOCKET RECEIVED DATA *** 111 ', data)
|
||||||
|
// });
|
||||||
|
|
||||||
// client-side
|
// client-side
|
||||||
socket.on("connect", () => {
|
socket.on("connect", () => {
|
||||||
console.log(socket.id);
|
console.log(socket.id);
|
||||||
|
|||||||
@@ -6,5 +6,6 @@ export const socketEmitEvents = {
|
|||||||
|
|
||||||
export const socketOnEvents = {
|
export const socketOnEvents = {
|
||||||
receive_message: 'receive_message',
|
receive_message: 'receive_message',
|
||||||
|
refresh_all_actions: 'refresh_all_actions',
|
||||||
refresh_provision: 'refresh_provision_actions'
|
refresh_provision: 'refresh_provision_actions'
|
||||||
}
|
}
|
||||||
@@ -41,22 +41,27 @@ export default function Products() {
|
|||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<div className="row m-b-20">
|
<div className="row m-b-20">
|
||||||
{products && products.map((product, index) => (
|
{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`}>
|
{
|
||||||
|
// 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)} >
|
<Link to={productPath(product?.product_id)} >
|
||||||
<div className={`d-flex align-items-center extraProductCard ${product?.icon_style}`} style={{borderColor:'black', borderWidth: '2px'}} >
|
<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">
|
<div className="icon-container img-icon m-r-20 bg-light-gray rounded">
|
||||||
<i className={`fa ${product?.product_icon} text-primary`}></i>
|
<i className={`fa ${product?.product_icon} text-primary`}></i>
|
||||||
</div>
|
</div>
|
||||||
<div className="report-details">
|
<div className="report-details overflow-hidden">
|
||||||
<p><span style={{fontWeight: 'bolder', color: '#00557A'}}>{product?.status_text}</span></p>
|
<p><span style={{fontWeight: 'bolder', color: '#00557A'}}>{product?.status_text}</span></p>
|
||||||
<h4><span style={{paddingLeft: '10px'}}>{product?.name}</span></h4>
|
<h4><span className='w-100 d-inline-block text-truncate' style={{paddingLeft: '10px'}}>{product?.name}</span></h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
)
|
||||||
|
}
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div className="apexchart-wrapper">
|
<div className="apexchart-wrapper">
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export default function ProductsURL() {
|
|||||||
{/*<a className="btn btn-xs" href="#!">Export <i className="zmdi zmdi-download pl-1"></i> </a>*/}
|
{/*<a className="btn btn-xs" href="#!">Export <i className="zmdi zmdi-download pl-1"></i> </a>*/}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="card-body scrollbar scroll_dark pt-0" style={{maxHeight: '350px'}}>
|
<div className="overflow-y-auto card-body scrollbar scroll_dark pt-0" style={{maxHeight: '350px'}}>
|
||||||
<div className="datatable-wrapper table-responsive">
|
<div className="datatable-wrapper table-responsive">
|
||||||
{isFetching ?
|
{isFetching ?
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ export default function RecentActions() {
|
|||||||
<h4>{dataAction?.data?.completed}</h4>
|
<h4>{dataAction?.data?.completed}</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="table-responsive m-t-20">
|
<div className="overflow-y-auto table-responsive m-t-20">
|
||||||
<table id="datatable-buttons" className="table">
|
<table id="datatable-buttons" className="table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -94,7 +94,7 @@ export default function RecentActions() {
|
|||||||
let text = action?.status == '5' ? 'completed' : action?.status == '3' ? 'verifying' : action?.status == '0' ? 'processing' : 'processing'
|
let text = action?.status == '5' ? 'completed' : action?.status == '3' ? 'verifying' : action?.status == '0' ? 'processing' : 'processing'
|
||||||
return (
|
return (
|
||||||
<tr key={index}>
|
<tr key={index}>
|
||||||
<td>{action?.id}</td>
|
<td>{(action?.id).toString().slice(-4)}</td>
|
||||||
<td>{action?.action_label}</td>
|
<td>{action?.action_label}</td>
|
||||||
<td>{new Date(action?.added).toDateString()}</td>
|
<td>{new Date(action?.added).toDateString()}</td>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export default function UserFooter(){
|
|||||||
<p>© Copyright {year}. All rights reserved.</p>
|
<p>© Copyright {year}. All rights reserved.</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="col col-sm-6 ml-sm-auto text-center text-sm-right">
|
<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 MERMS(AI)</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import siteLinks from "../../../links/siteLinks";
|
|||||||
|
|
||||||
export default function UserHeader(){
|
export default function UserHeader(){
|
||||||
|
|
||||||
const { userDetails } = useSelector((state) => state?.userDetails); // CHECKS IF USER Details are avaliable, to determine if user is active
|
const { userDetails } = useSelector((state) => state?.userDetails); // USER Details
|
||||||
|
|
||||||
const nav_menu = useRef(null)
|
const nav_menu = useRef(null)
|
||||||
|
|
||||||
@@ -74,10 +74,15 @@ export default function UserHeader(){
|
|||||||
<ul className="navbar-nav nav-right ml-auto">
|
<ul className="navbar-nav nav-right ml-auto">
|
||||||
<li className="nav-item user-profile">
|
<li className="nav-item user-profile">
|
||||||
<a onClick={toggleMenu} className="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdow">
|
<a onClick={toggleMenu} className="nav-link dropdown-toggle" role="button" data-bs-toggle="dropdow">
|
||||||
<img src={getImage('profile-pic-circle.png')} alt="avtar-img" />
|
<img
|
||||||
|
src={userDetails?.picture ? userDetails?.picture : getImage('profile-pic-circle.png')}
|
||||||
|
// src={getImage('profile-pic-circle.png')}
|
||||||
|
alt="avtar-img"
|
||||||
|
/>
|
||||||
<span className="bg-success user-status"></span>
|
<span className="bg-success user-status"></span>
|
||||||
</a>
|
</a>
|
||||||
<div ref={nav_menu} onClick={toggleMenu} className="dropdown-menu animated fadeIn">
|
<div ref={nav_menu} onClick={toggleMenu} className="dropdown-menu animated fadeIn">
|
||||||
|
<div className="position-fixed" style={{top: '0px', left: '0px', right: '0px', bottom: '0px'}}></div>
|
||||||
<div className="bg-gradient px-4 py-3">
|
<div className="bg-gradient px-4 py-3">
|
||||||
<div className="d-flex align-items-center justify-content-between">
|
<div className="d-flex align-items-center justify-content-between">
|
||||||
<div className="mr-1">
|
<div className="mr-1">
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ export default function UserMenu() {
|
|||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
<ul id="collapseTwo" className="collapse" aria-labelledby="headingTwo" data-bs-parent="#sidebarNav">
|
<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.subscription ? 'active' : ''}`}><Link to={siteLinks.subscription}>Subscription</Link></li>
|
||||||
<li className={`${pathname == siteLinks.settings ? 'active' : ''}`}><Link to={siteLinks.settings}>Settings</Link></li>
|
<li className={`${pathname == siteLinks.settings ? 'active' : ''}`}><Link to={siteLinks.settings}>Settings</Link></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -0,0 +1,248 @@
|
|||||||
|
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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="card-body">
|
<div className="card-body" style={{minHeight: '600px', maxHeight: '600px'}}>
|
||||||
<iframe ref={iframe} style={{borderWidth: '0px'}} src={externalUrl} width="100%" height="600" title={externalUrl}></iframe>
|
<iframe ref={iframe} style={{borderWidth: '0px'}} src={externalUrl} width="100%" height="600" title={externalUrl}></iframe>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 ml-auto">
|
<div className="p-4 ml-auto">
|
||||||
@@ -87,7 +87,7 @@ export default function ProductActive({productData}){
|
|||||||
<h4 className="card-title"> Site Settings </h4>
|
<h4 className="card-title"> Site Settings </h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="card-body">
|
<div className="card-body" style={{minHeight: '680px'}}>
|
||||||
<Settings productData={productData} />
|
<Settings productData={productData} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ export default function ProductStart(props){
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Vertical Center Modal */}
|
{/* Vertical Center Modal */}
|
||||||
<div ref={modalRef} className="modal fade" id="verticalCenter" tabIndex="-1" role="dialog" aria-hidden="true">
|
<div ref={modalRef} className="modal fade" id="verticalCenter" tabIndex="-1" role="dialog" aria-hidden="false">
|
||||||
<div className="modal-dialog modal-dialog-centered" role="document">
|
<div className="modal-dialog modal-dialog-centered" role="document">
|
||||||
<div className="modal-content">
|
<div className="modal-content">
|
||||||
<div className="modal-header">
|
<div className="modal-header">
|
||||||
|
|||||||
@@ -1,6 +1,179 @@
|
|||||||
const ColorStyleConfigure =()=>{
|
import React, {memo} from 'react'
|
||||||
|
import getImage from "../../../utils/getImage";
|
||||||
|
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query';
|
||||||
|
import queryKeys from '../../../services/queryKeys';
|
||||||
|
import {
|
||||||
|
getProductcolorStyleCss,
|
||||||
|
activateTemplate,
|
||||||
|
getProductColorStyles,
|
||||||
|
activateColorStyle
|
||||||
|
} from '../../../services/services';
|
||||||
|
import {Link} from "react-router-dom";
|
||||||
|
import siteLinks from "../../../links/siteLinks";
|
||||||
|
|
||||||
return <>COLOR CONFIG</>
|
const ColorStyleConfigure = memo(({name = 'Full Name', data, productData}) => {
|
||||||
|
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
const {data: colorStyleCss, isFetching, isError, error} = useQuery({
|
||||||
|
queryKey: queryKeys.productcolorStyleCss,
|
||||||
|
queryFn: () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
product_id: productData?.product_id
|
||||||
}
|
}
|
||||||
|
return getProductColorStyles(reqData)
|
||||||
|
},
|
||||||
|
staleTime: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
const templateResponse = colorStyleCss?.data
|
||||||
|
const currentColorUID = templateResponse?.current_colorstyle_uid
|
||||||
|
const color_styles = templateResponse?.color_styles
|
||||||
|
const custom_template_name = templateResponse?.custom_template_name
|
||||||
|
|
||||||
|
// console.log('data Template', templateResponse)
|
||||||
|
console.log("Page data == ", data)
|
||||||
|
|
||||||
|
const handleActivateTemplate = useMutation({
|
||||||
|
mutationFn: (fields) => {
|
||||||
|
return activateColorStyle(fields)
|
||||||
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
if (res?.data?.resultCode != '0') {
|
||||||
|
throw new Error(res.data.resultDescription)
|
||||||
|
}
|
||||||
|
queryClient.refetchQueries({ // refetches productProvision API call
|
||||||
|
queryKey: [...queryKeys.settingsData],
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onSettled: () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
handleActivateTemplate.reset()
|
||||||
|
}, 3000)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const handleSubmit = (style_uid) => {
|
||||||
|
const reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
product_id: productData?.product_id,
|
||||||
|
color_style_uid: style_uid
|
||||||
|
}
|
||||||
|
// console.log(reqData)
|
||||||
|
handleActivateTemplate.mutate(reqData)
|
||||||
|
}
|
||||||
|
if (custom_template_name && custom_template_name != '') {
|
||||||
|
// This implies we have a custom template , just return here
|
||||||
|
return <>
|
||||||
|
<div className='col-12'>
|
||||||
|
<div
|
||||||
|
className="rounded-2 d-flex flex-column justify-content-between align-items-center"
|
||||||
|
style={{backgroundColor: '#F2FAF7'}}>
|
||||||
|
<h4 className='p-4 text-black'
|
||||||
|
style={{marginBottom: '20px'}}>Custom Product Template.</h4>
|
||||||
|
<img className='' style={{width: '200px'}}
|
||||||
|
src={getImage('custom-template.png')}
|
||||||
|
alt='mail-alert'/>
|
||||||
|
<h4 className='p-4 text-black'
|
||||||
|
style={{marginTop: '20px'}}>This product is using a custom template named <span
|
||||||
|
style={{color: 'darkred'}}>“{custom_template_name}”</span> .</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<div className="page-account-form">
|
||||||
|
<div className="p-0">
|
||||||
|
{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="row overflow-y-auto" style={{maxHeight: '550px'}}>
|
||||||
|
<>
|
||||||
|
{!color_styles?.length ?
|
||||||
|
<p>No data Found</p>
|
||||||
|
:
|
||||||
|
color_styles.map(color_style => (
|
||||||
|
<div key={color_style.color_style_uid} className="col-xl-6 col-sm-6">
|
||||||
|
<div className="card card-statistics">
|
||||||
|
<div className="card-body" style={{
|
||||||
|
backgroundColor: `#${color_style.color_code}`,
|
||||||
|
opacity: '0.85',
|
||||||
|
borderRadius: '10px'
|
||||||
|
}}>
|
||||||
|
<div className="text-center p-2">
|
||||||
|
{/*<div className="mb-2">*/}
|
||||||
|
{/* <img src={getImage('file-icon/svg.png')}*/}
|
||||||
|
{/* alt={template.title}/>*/}
|
||||||
|
{/*</div>*/}
|
||||||
|
<h4 className="mb-0">{color_style.title}</h4>
|
||||||
|
{currentColorUID === color_style.color_style_uid ?
|
||||||
|
<button className="btn btn-light"
|
||||||
|
disabled={true}>Active</button>
|
||||||
|
:
|
||||||
|
<button
|
||||||
|
onClick={() => handleSubmit(color_style.color_style_uid)}
|
||||||
|
className="btn btn-primary">Select</button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
{/* {Object.entries(data)?.map(([key, value]) => (
|
||||||
|
<div key={key} className="col-xl-6 col-sm-6">
|
||||||
|
<div className="card card-statistics">
|
||||||
|
<div className="card-body">
|
||||||
|
<div className="text-center p-2">
|
||||||
|
<div className="mb-2">
|
||||||
|
<img src={getImage(value.banner)} alt={value.title} />
|
||||||
|
</div>
|
||||||
|
<h4 className="mb-0">{value.title}</h4>
|
||||||
|
<a href="javascript:void(0)" className="btn btn-light">Activate</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))} */}
|
||||||
|
</>
|
||||||
|
|
||||||
|
<div className="col-12">
|
||||||
|
<>
|
||||||
|
{handleActivateTemplate.isPending ?
|
||||||
|
<p className={'text-center '}>loading...</p>
|
||||||
|
:
|
||||||
|
handleActivateTemplate.isError ?
|
||||||
|
<p className={'text-center text-danger'}>{handleActivateTemplate.error.message}</p>
|
||||||
|
:
|
||||||
|
handleActivateTemplate.isSuccess ?
|
||||||
|
<p className={'text-center text-success'}>Templated activated
|
||||||
|
successfully</p>
|
||||||
|
:
|
||||||
|
null
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
export default ColorStyleConfigure
|
export default ColorStyleConfigure
|
||||||
@@ -112,9 +112,15 @@ const GeneralTab = memo(({
|
|||||||
<>
|
<>
|
||||||
{isCustom === true ?
|
{isCustom === true ?
|
||||||
<>
|
<>
|
||||||
{(tabKey === 'template_tab') && <SiteTemplateSelector name={name} data={sortedData} isCustom={isCustom} productData={productData}/>}
|
{(tabKey === 'template_tab') &&
|
||||||
{(tabKey === 'url_config_tab') && <URLConfiguration name={name} data={sortedData} isCustom={isCustom} productData={productData}/>}
|
<SiteTemplateSelector name={name} data={sortedData} isCustom={isCustom}
|
||||||
{(tabKey === 'color_scheme_tab') && <ColorStyleConfigure name={name} data={sortedData} isCustom={isCustom} productData={productData}/>}
|
productData={productData}/>}
|
||||||
|
{(tabKey === 'url_config_tab') &&
|
||||||
|
<URLConfiguration name={name} data={sortedData} isCustom={isCustom}
|
||||||
|
productData={productData}/>}
|
||||||
|
{(tabKey === 'color_scheme_tab') &&
|
||||||
|
<ColorStyleConfigure name={name} data={sortedData} isCustom={isCustom}
|
||||||
|
productData={productData}/>}
|
||||||
</>
|
</>
|
||||||
:
|
:
|
||||||
<div className="page-account-form">
|
<div className="page-account-form">
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import queryKeys from '../../../services/queryKeys';
|
|||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { useQuery } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
import sortObjectByListOrder from '../../../helpers/sortObjectByListOrder'
|
import sortObjectByListOrder from '../../../helpers/sortObjectByListOrder'
|
||||||
|
import TemplateConfigure from './TemplateConfigure';
|
||||||
|
|
||||||
const Settings = memo(({productData}) => {
|
const Settings = memo(({productData}) => {
|
||||||
|
|
||||||
@@ -24,7 +25,7 @@ const Settings = memo(({productData}) => {
|
|||||||
})
|
})
|
||||||
const settingsConfig = configData?.data?.settings_items
|
const settingsConfig = configData?.data?.settings_items
|
||||||
// console.log('CONFIG DATA...', settingsConfig)
|
// console.log('CONFIG DATA...', settingsConfig)
|
||||||
|
// console.log('configData', configData?.data?.subscription_template)
|
||||||
|
|
||||||
const [fieldsChanged, setFieldsChanged] = useState(false)
|
const [fieldsChanged, setFieldsChanged] = useState(false)
|
||||||
|
|
||||||
@@ -81,12 +82,12 @@ const Settings = memo(({productData}) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<div className="tab tab-vertical">
|
<div className="d-flex">
|
||||||
<ul className="nav nav-tabs" role="tablist">
|
<ul className="bg-body-secondary flex-column nav" role="tablist" style={{width: '25%', minHeight: '670px', maxHeight: '670px'}}>
|
||||||
<>
|
<>
|
||||||
{Object.entries(sortedSettingsConfig).map(([key, value], index) => (
|
{Object.entries(sortedSettingsConfig).map(([key, value], index) => (
|
||||||
<li key={key} className="nav-item">
|
<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}
|
id={key}
|
||||||
// data-bs-toggle="pill"
|
// data-bs-toggle="pill"
|
||||||
// data-bs-target={`#${value.controls}`}
|
// data-bs-target={`#${value.controls}`}
|
||||||
@@ -97,12 +98,27 @@ const Settings = memo(({productData}) => {
|
|||||||
onClick={()=>handleChangeTab(value.controls)}
|
onClick={()=>handleChangeTab(value.controls)}
|
||||||
>
|
>
|
||||||
{value.title}
|
{value.title}
|
||||||
</a>
|
</p>
|
||||||
</li>
|
</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>
|
</ul>
|
||||||
<div className="tab-content">
|
<div className="p-3 tab-content" style={{width: '75%'}}>
|
||||||
<>
|
<>
|
||||||
{Object.entries(sortedSettingsConfig).map(([key, value], index) => (
|
{Object.entries(sortedSettingsConfig).map(([key, value], index) => (
|
||||||
<div key={key} className={`tab-pane fade ${(activeTab == value.controls || (index == 0 & !activeTab)) && 'active show'}`}
|
<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} />
|
<GeneralTab tabKey={key} name={value.title} data={value.data} isCustom={value.custom} productData={productData} backendValues={settingsData} setFieldsChanged={setFieldsChanged} />
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
<div className={`tab-pane fade ${(activeTab == 'config_temp') && 'active show'}`}
|
||||||
|
>
|
||||||
|
<TemplateConfigure productData={productData} />
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ const SiteTemplateSelector = memo(({name = 'Full Name', data, productData}) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<div className="row">
|
<div className="row overflow-y-auto" style={{maxHeight: '550px'}}>
|
||||||
<>
|
<>
|
||||||
{!templates?.length ?
|
{!templates?.length ?
|
||||||
<p>No data Found</p>
|
<p>No data Found</p>
|
||||||
|
|||||||
@@ -0,0 +1,166 @@
|
|||||||
|
import React, { useState } from "react";
|
||||||
|
//import getImage from "../../../utils/getImage";
|
||||||
|
import { 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({});
|
||||||
|
|
||||||
|
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 = Array.isArray(templateResponse?.template_images?.data)
|
||||||
|
? templateResponse.template_images.data
|
||||||
|
: [];
|
||||||
|
console.log("templateResponse", templateResponse);
|
||||||
|
|
||||||
|
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",
|
||||||
|
width: "100%",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<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;
|
||||||
@@ -1,72 +1,80 @@
|
|||||||
import { Form, Formik } from "formik";
|
import { Form, Formik } from "formik";
|
||||||
import * as Yup from "yup";
|
import * as Yup from "yup";
|
||||||
import {useMutation} from '@tanstack/react-query';
|
import { useMutation } from "@tanstack/react-query";
|
||||||
import {setExternalURL} from '../../../services/services';
|
import { setExternalURL } from "../../../services/services";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
const validationSchema = Yup.object().shape({
|
const validationSchema = Yup.object().shape({
|
||||||
url: Yup.string().required("URL is required").matches(/^https?:\/\/[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-]+\.[a-zA-Z]+/, 'Must be like: https://example.mysite.com'),
|
url: Yup.string()
|
||||||
})
|
.required("URL is required")
|
||||||
|
.matches(
|
||||||
|
/^https?:\/\/[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-]+\.[a-zA-Z]+/,
|
||||||
|
"Must be like: https://example.mysite.com",
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
// const initialValues = {
|
// const initialValues = {
|
||||||
// url: '',
|
// url: '',
|
||||||
// };
|
// };
|
||||||
|
|
||||||
const URLConfiguration = ({ productData }) => {
|
const URLConfiguration = ({ productData }) => {
|
||||||
|
const [externalURLChanged, setExternalURLChanged] = useState(true);
|
||||||
const [externalURLChanged, setExternalURLChanged] = useState(true)
|
|
||||||
|
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
url: productData?.external_url || '',
|
url: productData?.external_url || "",
|
||||||
};
|
};
|
||||||
|
|
||||||
let defaultUrl = 'https://' + productData?.internal_url
|
let defaultUrl = "https://" + productData?.internal_url;
|
||||||
let externalUrl = productData?.external_url
|
let externalUrl = productData?.external_url;
|
||||||
|
|
||||||
const handleExternalURLChanged = (e) => {
|
const handleExternalURLChanged = (e) => {
|
||||||
if (e.target.value == externalUrl) {
|
if (e.target.value == externalUrl) {
|
||||||
setExternalURLChanged(true)
|
setExternalURLChanged(true);
|
||||||
} else {
|
} else {
|
||||||
setExternalURLChanged(false)
|
setExternalURLChanged(false);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// API to set url
|
// API to set url
|
||||||
const setURL = useMutation({
|
const setURL = useMutation({
|
||||||
mutationFn: (fields) => {
|
mutationFn: (fields) => {
|
||||||
return setExternalURL(fields)
|
return setExternalURL(fields);
|
||||||
},
|
},
|
||||||
onSuccess: (res) => {
|
onSuccess: (res) => {
|
||||||
if (res.data.resultCode != '0') {
|
if (res.data.resultCode != "0") {
|
||||||
// throw({message: res?.data?.resultDescription})
|
// throw({message: res?.data?.resultDescription})
|
||||||
throw({message: 'Something went wrong!'})
|
throw { message: "Something went wrong!" };
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onSettled: () => {
|
onSettled: () => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setURL.reset()
|
setURL.reset();
|
||||||
}, 3000)
|
}, 3000);
|
||||||
}
|
},
|
||||||
// onError: (err) => {
|
// onError: (err) => {
|
||||||
// console.log('err', err)
|
// console.log('err', err)
|
||||||
// }
|
// }
|
||||||
})
|
});
|
||||||
|
|
||||||
const handleSubmit = (values) => {
|
const handleSubmit = (values) => {
|
||||||
let reqData = {
|
let reqData = {
|
||||||
token: localStorage.getItem('token'), // USER TOKEN
|
token: localStorage.getItem("token"), // USER TOKEN
|
||||||
uid: localStorage.getItem('uid'), // USER UID
|
uid: localStorage.getItem("uid"), // USER UID
|
||||||
subscription_uid: productData?.subscription_uid,
|
subscription_uid: productData?.subscription_uid,
|
||||||
external_url: values.url
|
external_url: values.url,
|
||||||
}
|
};
|
||||||
setURL.mutate(reqData)
|
setURL.mutate(reqData);
|
||||||
}
|
};
|
||||||
|
|
||||||
return <>
|
return (
|
||||||
|
<>
|
||||||
<div className="card card-statistics">
|
<div className="card card-statistics">
|
||||||
<div className="card-header">
|
<div className="card-header">
|
||||||
<div className="card-heading">
|
<div className="card-heading">
|
||||||
<h4 className="card-title" style={{textTransform: 'none'}}>{defaultUrl}</h4>
|
<h4 className="card-title" style={{ textTransform: "none" }}>
|
||||||
|
{defaultUrl}
|
||||||
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/*<div className="card-body">*/}
|
{/*<div className="card-body">*/}
|
||||||
@@ -85,57 +93,104 @@ const URLConfiguration = ({productData}) => {
|
|||||||
>
|
>
|
||||||
{(props) => {
|
{(props) => {
|
||||||
return (
|
return (
|
||||||
<Form className='w-full'>
|
<Form className="w-full">
|
||||||
<div className="card card-statistics" style={{backgroundColor: '#b6e5ef'}}>
|
<div
|
||||||
|
className="card card-statistics"
|
||||||
|
style={{ backgroundColor: "#b6e5ef" }}
|
||||||
|
>
|
||||||
<div className="card-header">
|
<div className="card-header">
|
||||||
<div className="card-heading">
|
<div className="card-heading">
|
||||||
<h4 className="card-title" style={{textTransform: 'none'}}>Set your own URL</h4>
|
<h4
|
||||||
|
className="card-title"
|
||||||
|
style={{ textTransform: "none" }}
|
||||||
|
>
|
||||||
|
Set your own URL
|
||||||
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label htmlFor="exampleInputEmail1">Enter your full URL <span
|
<label htmlFor="exampleInputEmail1">
|
||||||
className={`${(props.errors.url && props.touched.url) && 'text-danger'}`}>{props.errors.url}</span></label>
|
Enter your full URL{" "}
|
||||||
<input value={props.values.url} onChange={(e)=>{props.handleChange(e); handleExternalURLChanged(e)}} type="text"
|
<span
|
||||||
className="form-control" id="url" aria-describedby="url"
|
className={`${props.errors.url && props.touched.url && "text-danger"}`}
|
||||||
placeholder="https://example.mysite.com"/>
|
>
|
||||||
|
{props.errors.url}
|
||||||
|
</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
value={props.values.url}
|
||||||
|
onChange={(e) => {
|
||||||
|
props.handleChange(e);
|
||||||
|
handleExternalURLChanged(e);
|
||||||
|
}}
|
||||||
|
type="text"
|
||||||
|
className="form-control"
|
||||||
|
id="url"
|
||||||
|
aria-describedby="url"
|
||||||
|
placeholder="https://example.mysite.com"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div style={{width: '100%', textAlign: 'right'}}>
|
<div style={{ width: "100%", textAlign: "right" }}>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={setURL.isPending || externalURLChanged}
|
disabled={setURL.isPending || externalURLChanged}
|
||||||
className="btn btn-primary"
|
className="btn btn-primary"
|
||||||
>
|
>
|
||||||
{setURL.isPending ? 'Loading...' : 'Submit'}
|
{setURL.isPending ? "Loading..." : "Submit"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{setURL.error &&
|
{setURL.error && (
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<p className='text-danger'>{setURL.error.message}</p>
|
<p className="text-danger">{setURL.error.message}</p>
|
||||||
</div>
|
</div>
|
||||||
}
|
)}
|
||||||
|
|
||||||
{setURL.isSuccess &&
|
{setURL.isSuccess && (
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<p className='text-success'>{'Completed successfully'}</p>
|
<p className="text-success">{"Completed successfully"}</p>
|
||||||
</div>
|
</div>
|
||||||
}
|
)}
|
||||||
<div style={{backgroundColor: '#94b8c0', borderRadius: '10px', padding: '10px'}}>
|
<div
|
||||||
Final steps to configure your URL:<br/>
|
style={{
|
||||||
DNS:<br/>
|
backgroundColor: "#148399",
|
||||||
DNS:<br/>
|
borderRadius: "10px",
|
||||||
DNS:<br/>
|
padding: "10px",
|
||||||
|
color: "white",
|
||||||
|
fontWeight: "bolder",
|
||||||
|
fontSize: "14px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
To link your domain to your website, update your DNS record to
|
||||||
|
point to our hosting provider.
|
||||||
|
<br />
|
||||||
|
<hr />
|
||||||
|
Enter the following DNS servers in your domain settings
|
||||||
|
<br />
|
||||||
|
{process.env.REACT_APP_DNS1}
|
||||||
|
<br />
|
||||||
|
{process.env.REACT_APP_DNS2}
|
||||||
|
<hr />
|
||||||
|
<Link
|
||||||
|
target="_blank"
|
||||||
|
to={process.env.REACT_APP_DNS_LINK}
|
||||||
|
style={{ color: "#f6f5f6" }}
|
||||||
|
>
|
||||||
|
Click here for detailed instructions.
|
||||||
|
</Link>
|
||||||
|
<hr />
|
||||||
|
After updating your DNS settings, click “Start Verification.”
|
||||||
|
You will receive a status notification within 24 hours.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</Formik>
|
</Formik>
|
||||||
|
|
||||||
</>
|
</>
|
||||||
}
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export default URLConfiguration
|
export default URLConfiguration;
|
||||||
|
|||||||
@@ -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,89 @@
|
|||||||
|
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)
|
||||||
|
},
|
||||||
|
staleTime: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
// console.log('DATA', data?.data)
|
||||||
|
const paymentReportData = data?.data?.payment || []
|
||||||
|
|
||||||
|
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>Added</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Amount</th>
|
||||||
|
<th>Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{paymentReportData.length > 0 ? paymentReportData.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<tr key={index}>
|
||||||
|
<td>{item?.added}</td>
|
||||||
|
<td>{item?.option_name}</td>
|
||||||
|
<td>{item?.currency}{item?.amount}</td>
|
||||||
|
<td>{item?.status}</td>
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
:
|
||||||
|
<tr>
|
||||||
|
<td colSpan={4} className='text-center'>No data found</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
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)
|
||||||
|
},
|
||||||
|
staleTime: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
// console.log('DATA', data?.data)
|
||||||
|
const productReportData = data?.data?.product || []
|
||||||
|
|
||||||
|
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>ID</th>
|
||||||
|
<th>Added</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{productReportData.length > 0 ? productReportData.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<tr key={index}>
|
||||||
|
<td>{item?.product_id}</td>
|
||||||
|
<td>{item?.added}</td>
|
||||||
|
<td>{item?.product_name}</td>
|
||||||
|
<td>{item?.status}</td>
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
:
|
||||||
|
<tr>
|
||||||
|
<td colSpan={4} className='text-center'>No data found</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,14 +1,99 @@
|
|||||||
import React from "react";
|
import React, { useState } from "react";
|
||||||
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
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() {
|
||||||
|
|
||||||
|
const [activeTab, setActiveTab] = useState('payment')
|
||||||
|
|
||||||
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<BreadcrumbComBS title='Reports' paths={['Dashboard', 'Reports']}/>
|
<BreadcrumbComBS title='Reports' paths={['Dashboard', 'Reports']}/>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="vh-100 col-12 flex align-items-center">Coming Soon</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>
|
||||||
|
<div>
|
||||||
|
<div className="card card-statistics" style={{minHeight: '500px'}}>
|
||||||
|
{/*<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" onClick={() => setActiveTab(item?.url)}>
|
||||||
|
<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>
|
||||||
|
|
||||||
|
{/* <!-- 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" style={{minHeight: '400px'}}>
|
||||||
|
{renderedTable[item?.url]}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div> */}
|
||||||
|
<div className="tab-content">
|
||||||
|
<div className={`tab-pane fade show active`} style={{minHeight: '400px'}}>
|
||||||
|
{renderedTable[activeTab]}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
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)
|
||||||
|
},
|
||||||
|
staleTime: 0
|
||||||
|
})
|
||||||
|
|
||||||
|
// console.log('DATA', data?.data)
|
||||||
|
const systemReportData = data?.data?.system || []
|
||||||
|
|
||||||
|
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>Added</th>
|
||||||
|
<th>Action Name</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Updated</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{systemReportData.length > 0 ? systemReportData.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<tr key={index}>
|
||||||
|
<td>{item?.added}</td>
|
||||||
|
<td>{item?.action_name}</td>
|
||||||
|
<td>{item?.status_description}</td>
|
||||||
|
<td>{item?.updated}</td>
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
:
|
||||||
|
<tr>
|
||||||
|
<td colSpan={4} className='text-center'>No data found</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
import React, { useRef, useState } from 'react'
|
||||||
|
import { Form, Formik } from "formik";
|
||||||
|
import * as Yup from "yup";
|
||||||
|
import { Modal } from "bootstrap";
|
||||||
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
|
import { updateLinks } from "../../services/services";
|
||||||
|
import queryKeys from '../../services/queryKeys';
|
||||||
|
|
||||||
|
|
||||||
|
const linksValidationSchema = Yup.object().shape({
|
||||||
|
facebook_url: Yup.string().matches(/^https:\/\/.+/,"URL must start with https://"),
|
||||||
|
twitter_url: Yup.string().matches(/^https:\/\/.+/,"URL must start with https://"),
|
||||||
|
blogger_url: Yup.string().matches(/^https:\/\/.+/,"URL must start with https://"),
|
||||||
|
google_url: Yup.string().matches(/^https:\/\/.+/,"URL must start with https://"),
|
||||||
|
linked_url: Yup.string().matches(/^https:\/\/.+/,"URL must start with https://"),
|
||||||
|
website_url: Yup.string().matches(/^https:\/\/.+/,"URL must start with https://"),
|
||||||
|
})
|
||||||
|
|
||||||
|
export default function LinksForm({data}) {
|
||||||
|
const modalRef = useRef(null)
|
||||||
|
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
const [intialData] = useState(data)
|
||||||
|
|
||||||
|
const [infoToUpdate, setInfoToUpdate] = useState({})
|
||||||
|
|
||||||
|
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();
|
||||||
|
};
|
||||||
|
|
||||||
|
// UPDATE LINKS MUTATION
|
||||||
|
const updateLinksMutation = useMutation({
|
||||||
|
mutationFn: (fields) => {
|
||||||
|
return updateLinks(fields)
|
||||||
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
if(res.data.resultCode != '0'){
|
||||||
|
throw({message: res?.data?.resultDescription ? res?.data?.resultDescription : 'En error occured'})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSettled: ()=>{
|
||||||
|
setTimeout(() => {
|
||||||
|
dismissModal() //CLOSE MODAL HERE
|
||||||
|
queryClient.refetchQueries({
|
||||||
|
queryKey: [...queryKeys.profile_data], // type: 'active', // exact: true,
|
||||||
|
})
|
||||||
|
updateLinksMutation.reset()
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const handleSetInfoToUpdate = (values, helpers) => {
|
||||||
|
setInfoToUpdate(values)
|
||||||
|
var modal = new Modal(document.getElementById('modal_links'));
|
||||||
|
modal.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
const proceed = () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
url_list: {...infoToUpdate}
|
||||||
|
}
|
||||||
|
// console.log(reqData)
|
||||||
|
updateLinksMutation.mutate(reqData)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Formik
|
||||||
|
initialValues={intialData}
|
||||||
|
validationSchema={linksValidationSchema}
|
||||||
|
onSubmit={handleSetInfoToUpdate}
|
||||||
|
>
|
||||||
|
{(props) => {
|
||||||
|
return (
|
||||||
|
<Form className=''>
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="fb">Facebook URL: {(props.errors.facebook_url && props.touched.facebook_url) && <span className="text-danger">{props.errors.facebook_url}</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="facebook_url" value={props.values?.facebook_url} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="tr">Twitter URL: {(props.errors.twitter_url && props.touched.twitter_url) && <span className="text-danger">{props.errors.twitter_url}</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="twitter_url" value={props.values?.twitter_url} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="br">Blogger URL: {(props.errors.blogger_url && props.touched.blogger_url) && <span className="text-danger">{props.errors.blogger_url}</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="blogger_url" value={props.values?.blogger_url} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="go">Google+ URL: {(props.errors.google_url && props.touched.google_url) && <span className="text-danger">{props.errors.google_url}</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="google_url" value={props.values?.google_url} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="li">LinkedIn URL: {(props.errors.linked_url && props.touched.linked_url) && <span className="text-danger">{props.errors.linked_url}</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="linked_url" value={props.values?.linked_url} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="we">Website URL: {(props.errors.website_url && props.touched.website_url) && <span className="text-danger">{props.errors.website_url}</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="website_url" value={props.values?.website_url} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
<div style={{textAlign: "right"}}>
|
||||||
|
<button type="submit" className="btn btn-primary">Update Links
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Formik>
|
||||||
|
|
||||||
|
{/* Vertical Center Modal */}
|
||||||
|
<div ref={modalRef} className="modal fade" id="modal_links" tabIndex="-1" role="dialog" aria-hidden="true">
|
||||||
|
<div className="modal-dialog modal-dialog-centered" role="document">
|
||||||
|
<div className="modal-content">
|
||||||
|
<div className="modal-header">
|
||||||
|
{/* <h5 className="modal-title" style={{fontSize: '18px'}} id="verticalCenterTitle">{'productTitle'}</h5> */}
|
||||||
|
<button type="button" className="close" data-bs-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="modal-body">
|
||||||
|
<h5 className="text-center" style={{fontSize: '18px'}}>Are you sure, you want to update?</h5>
|
||||||
|
{(updateLinksMutation.error || updateLinksMutation.isSuccess) && (
|
||||||
|
<div className="col-12">
|
||||||
|
<p className={`p-2 text-center ${updateLinksMutation.isSuccess ? 'text-success' : 'text-danger'}`}>
|
||||||
|
{updateLinksMutation.isSuccess ? 'Updated Successfully' : updateLinksMutation.error.message}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="modal-footer">
|
||||||
|
<button type="button" className="btn btn-danger" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
<button type="button" className="btn btn-primary" disabled={updateLinksMutation.isSuccess} onClick={proceed}>{updateLinksMutation.isPending ? 'Updating...' : 'Update'}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* END of Vertical Center Modal */}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
import React, { useRef, useState } from 'react'
|
||||||
|
import { Form, Formik } from "formik";
|
||||||
|
import * as Yup from "yup";
|
||||||
|
import { Modal } from "bootstrap";
|
||||||
|
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||||
|
import { updateProfile } from "../../services/services";
|
||||||
|
import queryKeys from '../../services/queryKeys';
|
||||||
|
import { useDispatch } from 'react-redux';
|
||||||
|
import { updateUserDetails } from '../../store/UserDetails'
|
||||||
|
|
||||||
|
const profileValidationSchema = Yup.object().shape({
|
||||||
|
firstname: Yup.string().required("firstname is required"),
|
||||||
|
lastname: Yup.string().required("lastname is required"),
|
||||||
|
email: Yup.string().required("email is required"),
|
||||||
|
account_name: Yup.string().required("account name is required"),
|
||||||
|
phone: Yup.string().required("phone is required"),
|
||||||
|
full_address: Yup.string().required("full address is required"),
|
||||||
|
})
|
||||||
|
|
||||||
|
export default function ProfileForm({data}) {
|
||||||
|
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
|
const modalRef = useRef(null)
|
||||||
|
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
const [intialData] = useState(data)
|
||||||
|
|
||||||
|
const [infoToUpdate, setInfoToUpdate] = useState({})
|
||||||
|
|
||||||
|
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();
|
||||||
|
};
|
||||||
|
|
||||||
|
// UPDATE PROFILE MUTATION
|
||||||
|
const updateProfileMutation = useMutation({
|
||||||
|
mutationFn: (fields) => {
|
||||||
|
return updateProfile(fields)
|
||||||
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
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 }));
|
||||||
|
},
|
||||||
|
onSettled: ()=>{
|
||||||
|
setTimeout(() => {
|
||||||
|
dismissModal() //CLOSE MODAL HERE
|
||||||
|
queryClient.refetchQueries({
|
||||||
|
queryKey: [...queryKeys.profile_data], // type: 'active', // exact: true,
|
||||||
|
})
|
||||||
|
updateProfileMutation.reset()
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
const handleSetInfoToUpdate = (values, helpers) => {
|
||||||
|
delete values.email
|
||||||
|
delete values.country
|
||||||
|
delete values?.picture
|
||||||
|
setInfoToUpdate(values)
|
||||||
|
var modal = new Modal(document.getElementById('modal'));
|
||||||
|
modal.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
const proceed = () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
...infoToUpdate
|
||||||
|
}
|
||||||
|
updateProfileMutation.mutate(reqData)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Formik
|
||||||
|
initialValues={intialData}
|
||||||
|
validationSchema={profileValidationSchema}
|
||||||
|
onSubmit={handleSetInfoToUpdate}
|
||||||
|
>
|
||||||
|
{(props) => {
|
||||||
|
return (
|
||||||
|
<Form className=''>
|
||||||
|
<div className="form-row">
|
||||||
|
<div className="form-group col-md-12">
|
||||||
|
<label htmlFor="name1">First Name {(props.errors.firstname && props.touched.firstname) && <span className="text-danger">{props.errors.firstname}*</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="firstname" value={props.values?.firstname} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
<div className="form-group col-md-12">
|
||||||
|
<label htmlFor="name1">Last Name {(props.errors.lastname && props.touched.lastname) && <span className="text-danger">{props.errors.lastname}*</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="lastname" value={props.values?.lastname} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
<div className="form-group col-md-12">
|
||||||
|
<label htmlFor="name1">Account Name {(props.errors.account_name && props.touched.account_name) && <span className="text-danger">{props.errors.account_name}*</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="account_name" value={props.values?.account_name} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
<div className="form-group col-md-12">
|
||||||
|
<label htmlFor="phone1">Phone Number {(props.errors.phone && props.touched.phone) && <span className="text-danger">{props.errors.phone}*</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="phone" value={props.values?.phone} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
<div className="form-group col-md-12">
|
||||||
|
<label htmlFor="email1">Email {(props.errors.email && props.touched.email) && <span className="text-danger">{props.errors.email}*</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="email" readOnly value={props.values?.email} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label htmlFor="add1">Address {(props.errors.full_address && props.touched.full_address) && <span className="text-danger">{props.errors.full_address}*</span>}</label>
|
||||||
|
<input type="text" className="form-control" name="full_address" value={props.values?.full_address} onChange={props.handleChange} />
|
||||||
|
</div>
|
||||||
|
<div style={{textAlign: "right"}}>
|
||||||
|
<button type="submit" className="btn btn-primary">Update Profile
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Formik>
|
||||||
|
|
||||||
|
{/* Vertical Center Modal */}
|
||||||
|
<div ref={modalRef} className="modal fade" id="modal" tabIndex="-1" role="dialog" aria-hidden="true">
|
||||||
|
<div className="modal-dialog modal-dialog-centered" role="document">
|
||||||
|
<div className="modal-content">
|
||||||
|
<div className="modal-header">
|
||||||
|
{/* <h5 className="modal-title" style={{fontSize: '18px'}} id="verticalCenterTitle">{'productTitle'}</h5> */}
|
||||||
|
<button type="button" className="close" data-bs-dismiss="modal" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="modal-body">
|
||||||
|
<h5 className="text-center" style={{fontSize: '18px'}}>Are you sure, you want to update?</h5>
|
||||||
|
{(updateProfileMutation.error || updateProfileMutation.isSuccess) && (
|
||||||
|
<div className="col-12">
|
||||||
|
<p className={`p-2 text-center ${updateProfileMutation.isSuccess ? 'text-success' : 'text-danger'}`}>
|
||||||
|
{updateProfileMutation.isSuccess ? 'Updated Successfully' : updateProfileMutation.error.message}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="modal-footer">
|
||||||
|
<button type="button" className="btn btn-danger" data-bs-dismiss="modal">Cancel</button>
|
||||||
|
<button type="button" className="btn btn-primary" disabled={updateProfileMutation.isSuccess} onClick={proceed}>{updateProfileMutation.isPending ? 'Updating...' : 'Update'}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* END of Vertical Center Modal */}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
import React, { memo, useRef, useState } from 'react'
|
||||||
|
import { useSelector, useDispatch } from 'react-redux';
|
||||||
|
import getImage from '../../utils/getImage';
|
||||||
|
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import { uploadProfileImg } from '../../services/services';
|
||||||
|
import queryKeys from '../../services/queryKeys';
|
||||||
|
import { updateUserDetails } from '../../store/UserDetails'
|
||||||
|
|
||||||
|
const ProfileImage = memo(({intialData}) => {
|
||||||
|
|
||||||
|
const dispatch = useDispatch()
|
||||||
|
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
const [selectedImg, setSelectedImg] = useState(null)
|
||||||
|
|
||||||
|
// const {userDetails} = useSelector((state) => state?.userDetails); // CHECKS FOR ACTIVE USER DETAILS
|
||||||
|
|
||||||
|
const avtarImage = "avtar/merms-user.png";
|
||||||
|
|
||||||
|
// browser profile img
|
||||||
|
const browserImg = useRef(null);
|
||||||
|
const browseProfileImg = () => {
|
||||||
|
browserImg.current.click();
|
||||||
|
};
|
||||||
|
|
||||||
|
const profileImgChangeHandler = (event) => {
|
||||||
|
setSelectedImg(event.target.files[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
const uploadProfileMutation = useMutation({
|
||||||
|
mutationFn: (fields) => {
|
||||||
|
if(!fields.file){
|
||||||
|
throw new Error('Please, select an image')
|
||||||
|
}
|
||||||
|
return uploadProfileImg(fields)
|
||||||
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
console.log('res', res)
|
||||||
|
if(res?.data?.picture){
|
||||||
|
dispatch(updateUserDetails({ picture: res?.data?.picture }));
|
||||||
|
}
|
||||||
|
// 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
|
||||||
|
},
|
||||||
|
onSettled: ()=>{
|
||||||
|
setTimeout(() => {
|
||||||
|
// queryClient.refetchQueries({
|
||||||
|
// queryKey: [...queryKeys.profile_data], // type: 'active', // exact: true,
|
||||||
|
// })
|
||||||
|
uploadProfileMutation.reset()
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const proceedToUpload = () => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem('token'), // USER TOKEN
|
||||||
|
member_uid: localStorage.getItem('uid'), // USER UID
|
||||||
|
file: selectedImg
|
||||||
|
}
|
||||||
|
// console.log('reqData', reqData)
|
||||||
|
uploadProfileMutation.mutate(reqData)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="col-xl-3 pb-xl-0 pb-5 border-right">
|
||||||
|
<div className="page-account-profil pt-5">
|
||||||
|
<div className="profile-img text-center rounded-circle">
|
||||||
|
<div className="pt-5">
|
||||||
|
<div className="bg-img m-auto">
|
||||||
|
<img
|
||||||
|
src={selectedImg ? URL.createObjectURL(selectedImg) : intialData?.personal_data?.picture ? intialData?.personal_data?.picture : getImage(avtarImage)}
|
||||||
|
// src={getImage(avtarImage)}
|
||||||
|
className="img-fluid" alt="user"
|
||||||
|
/>
|
||||||
|
<input
|
||||||
|
ref={browserImg}
|
||||||
|
className='d-none'
|
||||||
|
type='file'
|
||||||
|
accept="image/*"
|
||||||
|
onChange={(e) => profileImgChangeHandler(e)}
|
||||||
|
id='profile-image'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="profile pt-4">
|
||||||
|
<h4 className="mb-1">{intialData?.personal_data?.lastname} {intialData?.personal_data?.firstname}</h4>
|
||||||
|
<div style={{padding: '10px'}}>
|
||||||
|
<hr/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="profile-btn text-center">
|
||||||
|
<div>
|
||||||
|
<button onClick={browseProfileImg} className="btn btn-light text-primary mb-2">Change
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{selectedImg &&
|
||||||
|
<div>
|
||||||
|
<button onClick={proceedToUpload} disabled={uploadProfileMutation.isSuccess || uploadProfileMutation.isPending} className="btn btn-light text-primary mb-2">
|
||||||
|
{uploadProfileMutation.isPending ? 'Upload...' : 'Upload New Avatar'}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
{/* success or error message */}
|
||||||
|
{(uploadProfileMutation.isSuccess || uploadProfileMutation.isError) &&
|
||||||
|
<div>
|
||||||
|
<p className={`${uploadProfileMutation.isSuccess ? 'text-success' : 'text-danger'}`}>
|
||||||
|
{uploadProfileMutation.isSuccess ? 'Uploaded successfully' : uploadProfileMutation.error.message}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
export default ProfileImage
|
||||||
@@ -1,36 +1,14 @@
|
|||||||
import React, { useEffect, useMemo, useState } from "react";
|
import React, { useMemo, useState } from "react";
|
||||||
import { Form, Formik } from "formik";
|
|
||||||
import * as Yup from "yup";
|
|
||||||
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
|
||||||
import getImage from "../../utils/getImage";
|
//import getImage from "../../utils/getImage";
|
||||||
import queryKeys from "../../services/queryKeys";
|
import queryKeys from "../../services/queryKeys";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { profileDetails } from "../../services/services";
|
import { profileDetails } from "../../services/services";
|
||||||
|
import ProfileForm from "./ProfileForm";
|
||||||
|
import LinksForm from "./LinksForm";
|
||||||
|
import ProfileImage from "./ProfileImage";
|
||||||
|
|
||||||
const profileValidationSchema = Yup.object().shape({
|
|
||||||
// firstname: Yup.string().required("firstname is required"),
|
|
||||||
// lastname: Yup.string().required("lastname is required"),
|
|
||||||
// email: Yup.string().required("email is required"),
|
|
||||||
// account_name: Yup.string().required("account name is required"),
|
|
||||||
// phone: Yup.string().required("phone is required"),
|
|
||||||
// full_address: Yup.string().required("full address is required"),
|
|
||||||
})
|
|
||||||
|
|
||||||
const linksValidationSchema = Yup.object().shape({
|
|
||||||
// facebook_url: Yup.string().required("facebook is required"),
|
|
||||||
// twitter_url: Yup.string().required("twitter is required"),
|
|
||||||
// blogger_url: Yup.string().required("blog is required"),
|
|
||||||
// google_url: Yup.string().required("google is required"),
|
|
||||||
// linked_url: Yup.string().required("linkedin is required"),
|
|
||||||
// website_url: Yup.string().required("website is required"),
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
export default function Settings() {
|
export default function Settings() {
|
||||||
const avtarImage = "avtar/merms-user.png";
|
|
||||||
|
|
||||||
const [intialData, setInitialData] = useState({
|
const [intialData, setInitialData] = useState({
|
||||||
external_links: {},
|
external_links: {},
|
||||||
@@ -54,15 +32,6 @@ export default function Settings() {
|
|||||||
},[profileInfo])
|
},[profileInfo])
|
||||||
// console.log('INI', intialData)
|
// console.log('INI', intialData)
|
||||||
|
|
||||||
|
|
||||||
const updateProfile = (values, helpers) => {
|
|
||||||
console.log('Values', values)
|
|
||||||
}
|
|
||||||
|
|
||||||
const updateLinks = (values, helpers) => {
|
|
||||||
console.log('Values', values)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<BreadcrumbComBS title='Settings' paths={['Dashboard', 'Settings']}/>
|
<BreadcrumbComBS title='Settings' paths={['Dashboard', 'Settings']}/>
|
||||||
@@ -90,131 +59,14 @@ export default function Settings() {
|
|||||||
<div className="card card-statistics">
|
<div className="card card-statistics">
|
||||||
<div className="card-body p-0" style={{backgroundColor: "#f9f9fb"}}>
|
<div className="card-body p-0" style={{backgroundColor: "#f9f9fb"}}>
|
||||||
<div className="row no-gutters">
|
<div className="row no-gutters">
|
||||||
<div className="col-xl-3 pb-xl-0 pb-5 border-right">
|
<ProfileImage intialData={intialData} />
|
||||||
<div className="page-account-profil pt-5">
|
|
||||||
<div className="profile-img text-center rounded-circle">
|
|
||||||
<div className="pt-5">
|
|
||||||
<div className="bg-img m-auto">
|
|
||||||
{/*<img src="assets/img/avtar/01.jpg" className="img-fluid"*/}
|
|
||||||
{/* alt="users-avatar" />*/}
|
|
||||||
<img src={getImage(avtarImage)}
|
|
||||||
className="img-fluid" alt="user"/>
|
|
||||||
</div>
|
|
||||||
<div className="profile pt-4">
|
|
||||||
<h4 className="mb-1">{intialData?.personal_data?.lastname} {intialData?.personal_data?.firstname}</h4>
|
|
||||||
<div style={{padding: '10px'}}>
|
|
||||||
<hr/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="profile-btn text-center">
|
|
||||||
<div>
|
|
||||||
<button className="btn btn-light text-primary mb-2">Upload New Avatar
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{/*<div>*/}
|
|
||||||
{/* <button className="btn btn-danger">Delete</button>*/}
|
|
||||||
{/*</div>*/}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="col-xl-5 col-md-6 col-12 border-t border-right">
|
<div className="col-xl-5 col-md-6 col-12 border-t border-right">
|
||||||
<div className="page-account-form">
|
<div className="page-account-form">
|
||||||
<div className="form-titel border-bottom p-3">
|
<div className="form-titel border-bottom p-3">
|
||||||
<h5 className="mb-0 py-2">Edit Your Personal Settings</h5>
|
<h5 className="mb-0 py-2">Edit Your Personal Settings</h5>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
<Formik
|
<ProfileForm data={intialData.personal_data} />
|
||||||
initialValues={intialData?.personal_data}
|
|
||||||
validationSchema={profileValidationSchema}
|
|
||||||
onSubmit={updateProfile}
|
|
||||||
>
|
|
||||||
{(props) => {
|
|
||||||
return (
|
|
||||||
<Form className=''>
|
|
||||||
<div className="form-row">
|
|
||||||
<div className="form-group col-md-12">
|
|
||||||
<label htmlFor="name1">First Name {(props.errors.firstname && props.touched.firstname) && <span className="text-danger">*</span>}</label>
|
|
||||||
<input type="text" className="form-control" name="firstname" value={props.values?.firstname} onChange={props.handleChange} />
|
|
||||||
</div>
|
|
||||||
<div className="form-group col-md-12">
|
|
||||||
<label htmlFor="name1">Last Name {(props.errors.lastname && props.touched.lastname) && <span className="text-danger">*</span>}</label>
|
|
||||||
<input type="text" className="form-control" name="lastname" value={props.values?.lastname} onChange={props.handleChange} />
|
|
||||||
</div>
|
|
||||||
<div className="form-group col-md-12">
|
|
||||||
<label htmlFor="name1">Account Name {(props.errors.account_name && props.touched.account_name) && <span className="text-danger">*</span>}</label>
|
|
||||||
<input type="text" className="form-control" name="account_name" value={props.values?.account_name} onChange={props.handleChange} />
|
|
||||||
</div>
|
|
||||||
{/*<div className="form-group col-md-12">*/}
|
|
||||||
{/* <label htmlFor="title1">Email</label>*/}
|
|
||||||
{/* <input type="text" className="form-control" name="title1"*/}
|
|
||||||
{/* value="email@email.com" />*/}
|
|
||||||
{/*</div>*/}
|
|
||||||
<div className="form-group col-md-12">
|
|
||||||
<label htmlFor="phone1">Phone Number {(props.errors.phone && props.touched.phone) && <span className="text-danger">*</span>}</label>
|
|
||||||
<input type="text" className="form-control" name="phone" value={props.values?.phone} onChange={props.handleChange} />
|
|
||||||
</div>
|
|
||||||
<div className="form-group col-md-12">
|
|
||||||
<label htmlFor="email1">Email {(props.errors.email && props.touched.email) && <span className="text-danger">*</span>}</label>
|
|
||||||
<input type="text" className="form-control" name="email" value={props.values?.email} onChange={props.handleChange} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="form-group">
|
|
||||||
<label htmlFor="add1">Address {(props.errors.full_address && props.touched.full_address) && <span className="text-danger">*</span>}</label>
|
|
||||||
<input type="text" className="form-control" name="full_address" value={props.values?.full_address} onChange={props.handleChange} />
|
|
||||||
</div>
|
|
||||||
{/*<div className="form-group">*/}
|
|
||||||
{/* <label htmlFor="add2">Address 2</label>*/}
|
|
||||||
{/* <input type="text" className="form-control" id="add2"*/}
|
|
||||||
{/* value="1234 North Avenue Luke Lane, South Bend, IN 360001"/>*/}
|
|
||||||
{/*</div>*/}
|
|
||||||
|
|
||||||
{/*<div className="form-row">*/}
|
|
||||||
{/* <div className="form-group col-md-4">*/}
|
|
||||||
{/* <label htmlFor="inputState3">City</label>*/}
|
|
||||||
{/* <select id="inputState3" className="form-control">*/}
|
|
||||||
{/* <option>Choose...</option>*/}
|
|
||||||
{/* <option selected="">London</option>*/}
|
|
||||||
{/* <option>Montreal</option>*/}
|
|
||||||
{/* <option>Delhi</option>*/}
|
|
||||||
{/* <option>Tokyo</option>*/}
|
|
||||||
{/* </select>*/}
|
|
||||||
{/* </div>*/}
|
|
||||||
{/* <div className="form-group col-md-4">*/}
|
|
||||||
{/* <label htmlFor="inputState4">State</label>*/}
|
|
||||||
{/* <select id="inputState4" className="form-control">*/}
|
|
||||||
{/* <option>Choose...</option>*/}
|
|
||||||
{/* <option selected="">England</option>*/}
|
|
||||||
{/* <option>California</option>*/}
|
|
||||||
{/* <option>Texas</option>*/}
|
|
||||||
{/* <option>Scotland</option>*/}
|
|
||||||
{/* </select>*/}
|
|
||||||
{/* </div>*/}
|
|
||||||
{/* <div className="form-group col-md-4">*/}
|
|
||||||
{/* <label htmlFor="inputZip">Zip</label>*/}
|
|
||||||
{/* <input type="text" className="form-control" id="inputZip"*/}
|
|
||||||
{/* value="EC1A 1BB" />*/}
|
|
||||||
{/* </div>*/}
|
|
||||||
{/*</div>*/}
|
|
||||||
{/*<div className="form-group">*/}
|
|
||||||
{/* <div className="form-check">*/}
|
|
||||||
{/* <input className="form-check-input" type="checkbox"*/}
|
|
||||||
{/* id="gridCheck" />*/}
|
|
||||||
{/* <label className="form-check-label" htmlFor="gridCheck">*/}
|
|
||||||
{/* I agree to receive email notification.*/}
|
|
||||||
{/* </label>*/}
|
|
||||||
{/* </div>*/}
|
|
||||||
{/*</div>*/}
|
|
||||||
<div style={{textAlign: "right"}}>
|
|
||||||
<button type="submit" className="btn btn-primary">Update Profile
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</Form>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</Formik>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -224,50 +76,7 @@ export default function Settings() {
|
|||||||
<h5 className="mb-0 py-2">Your External Link</h5>
|
<h5 className="mb-0 py-2">Your External Link</h5>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
<Formik
|
<LinksForm data={intialData.external_links} />
|
||||||
initialValues={intialData?.external_links}
|
|
||||||
validationSchema={linksValidationSchema}
|
|
||||||
onSubmit={updateLinks}
|
|
||||||
>
|
|
||||||
{(props) => {
|
|
||||||
return (
|
|
||||||
<Form className=''>
|
|
||||||
<div className="form-group">
|
|
||||||
<label htmlFor="fb">Facebook URL: {(props.errors.facebook_url && props.touched.facebook_url) && <span className="text-danger">*</span>}</label>
|
|
||||||
<input type="text" className="form-control" name="facebook_url" value={props.values?.facebook_url} onChange={props.handleChange} />
|
|
||||||
</div>
|
|
||||||
<div className="form-group">
|
|
||||||
<label htmlFor="tr">Twitter URL: {(props.errors.twitter_url && props.touched.twitter_url) && <span className="text-danger">*</span>}</label>
|
|
||||||
<input type="text" className="form-control" name="twitter_url" value={props.values?.twitter_url} onChange={props.handleChange} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="form-group">
|
|
||||||
<label htmlFor="br">Blogger URL: {(props.errors.blogger_url && props.touched.blogger_url) && <span className="text-danger">*</span>}</label>
|
|
||||||
<input type="text" className="form-control" name="blogger_url" value={props.values?.blogger_url} onChange={props.handleChange} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="form-group">
|
|
||||||
<label htmlFor="go">Google+ URL: {(props.errors.google_url && props.touched.google_url) && <span className="text-danger">*</span>}</label>
|
|
||||||
<input type="text" className="form-control" name="google_url" value={props.values?.google_url} onChange={props.handleChange} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="form-group">
|
|
||||||
<label htmlFor="li">LinkedIn URL: {(props.errors.linked_url && props.touched.linked_url) && <span className="text-danger">*</span>}</label>
|
|
||||||
<input type="text" className="form-control" name="linked_url" value={props.values?.linked_url} onChange={props.handleChange} />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="form-group">
|
|
||||||
<label htmlFor="we">Website URL: {(props.errors.website_url && props.touched.website_url) && <span className="text-danger">*</span>}</label>
|
|
||||||
<input type="text" className="form-control" name="website_url" value={props.values?.website_url} onChange={props.handleChange} />
|
|
||||||
</div>
|
|
||||||
<div style={{textAlign: "right"}}>
|
|
||||||
<button type="submit" className="btn btn-primary">Update Links
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</Form>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</Formik>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2063,6 +2063,8 @@ ul.activity {
|
|||||||
.img-icon{
|
.img-icon{
|
||||||
width:60px;
|
width:60px;
|
||||||
height:60px;
|
height:60px;
|
||||||
|
min-width:60px;
|
||||||
|
min-height:60px;
|
||||||
border-radius:100px;
|
border-radius:100px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
line-height: 60px;
|
line-height: 60px;
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -6,7 +6,6 @@ import ReactDOM from 'react-dom/client';
|
|||||||
import { BrowserRouter } from 'react-router-dom';
|
import { BrowserRouter } from 'react-router-dom';
|
||||||
|
|
||||||
import App from './App';
|
import App from './App';
|
||||||
//import reportWebVitals from './reportWebVitals';
|
|
||||||
import 'bootstrap/dist/css/bootstrap.css';
|
import 'bootstrap/dist/css/bootstrap.css';
|
||||||
import 'bootstrap/dist/js/bootstrap.min.js'
|
import 'bootstrap/dist/js/bootstrap.min.js'
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const siteLinks = {
|
|||||||
comments: '/comments',
|
comments: '/comments',
|
||||||
reports: '/reports',
|
reports: '/reports',
|
||||||
subscription: '/subscription',
|
subscription: '/subscription',
|
||||||
|
my_media: '/my-files',
|
||||||
subscription_success:'/subscription-success',
|
subscription_success:'/subscription-success',
|
||||||
subscribe: '/subscribe',
|
subscribe: '/subscribe',
|
||||||
onboard: '/subscription',
|
onboard: '/subscription',
|
||||||
|
|||||||
@@ -8,9 +8,15 @@ const queryKeys = {
|
|||||||
recentAction: ['recent-action'],
|
recentAction: ['recent-action'],
|
||||||
settingsData: ['settings_data'],
|
settingsData: ['settings_data'],
|
||||||
myProductConfig: ['myproduct_config'],
|
myProductConfig: ['myproduct_config'],
|
||||||
|
myTemplateConfig: ['mytemplate_config'],
|
||||||
productTemplateData: ['product_template_data'],
|
productTemplateData: ['product_template_data'],
|
||||||
subscriptions: ['subscriptions'],
|
subscriptions: ['subscriptions'],
|
||||||
profile_data: ['profile_data'],
|
profile_data: ['profile_data'],
|
||||||
|
my_files: ['my_files'],
|
||||||
|
topics: ['topics'],
|
||||||
|
payment_report: ['payment_report'],
|
||||||
|
product_report: ['product_report'],
|
||||||
|
system_report: ['system_report'],
|
||||||
|
|
||||||
dashboard: ['dashboard'],
|
dashboard: ['dashboard'],
|
||||||
topBar: ['top-bar'],
|
topBar: ['top-bar'],
|
||||||
|
|||||||
+112
-4
@@ -1,10 +1,9 @@
|
|||||||
import axios from "axios"
|
import axios from "axios"
|
||||||
|
|
||||||
|
|
||||||
axios.interceptors.request.use(
|
axios.interceptors.request.use(
|
||||||
config => {
|
config => {
|
||||||
config.headers = {
|
config.headers = {
|
||||||
Accept: "application/json",
|
// Accept: "application/json",
|
||||||
"Access-Control-Allow-Origin": "*",
|
"Access-Control-Allow-Origin": "*",
|
||||||
// "Access-Control-Expose-Headers": "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",
|
// "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",
|
||||||
@@ -23,11 +22,20 @@ axios.interceptors.request.use(
|
|||||||
|
|
||||||
const postAuxEnd = (path, postData, media=false) => {
|
const postAuxEnd = (path, postData, media=false) => {
|
||||||
const basePath = media ? process.env.REACT_APP_MAIN_API : process.env.REACT_APP_MAIN_API
|
const basePath = media ? process.env.REACT_APP_MAIN_API : process.env.REACT_APP_MAIN_API
|
||||||
return axios.post(`${basePath}${path}`, postData).then(res => {
|
let newPostData = {}
|
||||||
|
if(!media){
|
||||||
|
newPostData = {...postData}
|
||||||
|
}else{
|
||||||
|
newPostData = new FormData();
|
||||||
|
for (let data in postData) {
|
||||||
|
newPostData.append(data, postData[data]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return axios.post(`${basePath}${path}`, newPostData).then(res => {
|
||||||
return res
|
return res
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
// console.log('res', err.response.data)
|
|
||||||
throw new Error(err.response.data.error_message);
|
throw new Error(err.response.data.error_message);
|
||||||
|
// throw new Error(err);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +92,22 @@ export const profileDetails = (reqData) => {
|
|||||||
return postAuxEnd(`/panel/account/profile`, postData, false)
|
return postAuxEnd(`/panel/account/profile`, postData, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO UPDATE PROFILE
|
||||||
|
export const updateProfile = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/account/profile-update`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO UPDATE LINKS
|
||||||
|
export const updateLinks = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/account/profilelinks-update`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
// FUNCTION TO GET PRODUCT BY ID
|
// FUNCTION TO GET PRODUCT BY ID
|
||||||
export const MyProductData = (reqData) => {
|
export const MyProductData = (reqData) => {
|
||||||
let postData = {
|
let postData = {
|
||||||
@@ -214,6 +238,20 @@ export const getProductTemplateData = (reqData) => {
|
|||||||
return postAuxEnd(`/panel/account/products/templates`, postData, false)
|
return postAuxEnd(`/panel/account/products/templates`, postData, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const getProductColorStyles = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...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
|
// FUNCTION TO ACTIVATE TEMPLATE
|
||||||
export const activateTemplate = (reqData) => {
|
export const activateTemplate = (reqData) => {
|
||||||
let postData = {
|
let postData = {
|
||||||
@@ -222,6 +260,14 @@ export const activateTemplate = (reqData) => {
|
|||||||
return postAuxEnd(`/panel/account/template/activate`, postData, false)
|
return postAuxEnd(`/panel/account/template/activate`, postData, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const activateColorStyle = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/panel/account/colorstyle/activate`, postData, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// FUNCTION TO GET PRODUCT SUBSCRIPTIONS
|
// FUNCTION TO GET PRODUCT SUBSCRIPTIONS
|
||||||
export const completeProfile = (reqData) => {
|
export const completeProfile = (reqData) => {
|
||||||
let postData = {
|
let postData = {
|
||||||
@@ -238,6 +284,59 @@ export const getSubscriptions = (reqData) => {
|
|||||||
return postAuxEnd(`/panel/subscription/products`, postData, false)
|
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
|
// FUNCTION TO GET COMMON PRACTICE
|
||||||
export const getCommonPractice = (reqData) => {
|
export const getCommonPractice = (reqData) => {
|
||||||
let postData = {
|
let postData = {
|
||||||
@@ -254,6 +353,15 @@ export const setExternalURL = (reqData) => {
|
|||||||
return postAuxEnd('/panel/myproduct/external-url', postData, false)
|
return postAuxEnd('/panel/myproduct/external-url', postData, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FUNCTION TO UPLOAD PROFILE IMAGE
|
||||||
|
export const uploadProfileImg = (reqData) => {
|
||||||
|
let postData = {
|
||||||
|
...reqData,
|
||||||
|
}
|
||||||
|
return postAuxEnd(`/upload/profile-picture`, postData, true)
|
||||||
|
// throw new Error('Opps')
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ export const userSlice = createSlice({
|
|||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
updateUserDetails: (state, action) => {
|
updateUserDetails: (state, action) => {
|
||||||
state.userDetails = { ...action.payload };
|
state.userDetails = { ...state.userDetails, ...action.payload };
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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