Compare commits
83 Commits
| 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 |
@@ -19,3 +19,11 @@ REACT_APP_TIMEOUT=600000
|
|||||||
# show download button
|
# show download button
|
||||||
REACT_APP_SHOW_DOWNLOAD=0
|
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
|
||||||
|
|
||||||
|
|||||||
@@ -20,3 +20,10 @@ REACT_APP_TIMEOUT=600000
|
|||||||
# show download button
|
# show download button
|
||||||
REACT_APP_SHOW_DOWNLOAD=0
|
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
|
||||||
|
|
||||||
|
|||||||
+9
-1
@@ -17,4 +17,12 @@ REACT_APP_TERMS_LINK='https://www.mermsemr.com/terms'
|
|||||||
REACT_APP_TIMEOUT=600000
|
REACT_APP_TIMEOUT=600000
|
||||||
|
|
||||||
# show download button
|
# show download button
|
||||||
REACT_APP_SHOW_DOWNLOAD=0
|
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
+12137
-5671
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",
|
||||||
|
|||||||
@@ -51,4 +51,11 @@ 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 |
@@ -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'
|
||||||
|
|
||||||
@@ -17,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(25, "Maximum 25 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() {
|
||||||
@@ -77,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>
|
||||||
</>
|
</>
|
||||||
:
|
:
|
||||||
|
|||||||
@@ -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'
|
||||||
|
|
||||||
@@ -26,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}))
|
||||||
@@ -34,13 +37,13 @@ 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)
|
||||||
@@ -69,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)
|
||||||
}
|
}
|
||||||
@@ -101,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">
|
||||||
@@ -120,12 +131,12 @@ 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>
|
||||||
|
|||||||
@@ -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'
|
||||||
@@ -33,6 +34,7 @@ const initialValues = {
|
|||||||
firstname: '',
|
firstname: '',
|
||||||
lastname: '',
|
lastname: '',
|
||||||
isChecked: false,
|
isChecked: false,
|
||||||
|
turnstileToken: '',
|
||||||
// username: '',
|
// username: '',
|
||||||
// password: ''
|
// password: ''
|
||||||
};
|
};
|
||||||
@@ -135,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
|
||||||
@@ -149,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>
|
||||||
</>
|
</>
|
||||||
|
|||||||
+243
-219
@@ -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({
|
||||||
@@ -65,50 +65,50 @@ export default function Comments() {
|
|||||||
const contactsCategory = getContactData?.data?.data?.category; // LIST OF CATEGORY
|
const contactsCategory = getContactData?.data?.data?.category; // LIST OF CATEGORY
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<BreadcrumbComBS title="Comments" paths={["Dashboard", "Comments"]} />
|
<BreadcrumbComBS title="Comments" paths={["Dashboard", "Comments"]} />
|
||||||
{getContactData?.isPending ? (
|
{getContactData?.isPending ? (
|
||||||
<>
|
<>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<p className="text-mute">Loading...</p>
|
<p className="text-mute">Loading...</p>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
) : getContactData?.error ? (
|
|
||||||
<div className="row">
|
|
||||||
<div className="col-12">
|
|
||||||
<p className="text-danger">{getContactData?.error?.message}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
</div>
|
||||||
<div className="row">
|
</>
|
||||||
{/*<div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/}
|
) : getContactData?.error ? (
|
||||||
<div className="col-12">
|
<div className="row">
|
||||||
<div
|
<div className="col-12">
|
||||||
className="card card-statistics mail-contant"
|
<p className="text-danger">{getContactData?.error?.message}</p>
|
||||||
style={{ minHeight: "200px", borderRadius: "10px" }}
|
</div>
|
||||||
>
|
</div>
|
||||||
<div className="card-body p-0">
|
) : (
|
||||||
<div className="row no-gutters">
|
<div className="row">
|
||||||
<div className="col-md-4 col-xxl-2 col-md-4">
|
{/*<div className="vh-100 col-12 flex align-items-center">Coming Soon</div>*/}
|
||||||
<div className="mail-sidebar">
|
<div className="col-12">
|
||||||
<div className="row justify-content-center">
|
<div
|
||||||
<div className="d-none col-12">
|
className="card card-statistics mail-contant"
|
||||||
<div className="text-center mail-sidebar-title px-4">
|
style={{ minHeight: "200px", borderRadius: "10px" }}
|
||||||
<a
|
>
|
||||||
href="#"
|
<div className="card-body p-0">
|
||||||
className="btn btn-primary btn-block py-3 font-weight-bold font-18"
|
<div className="row no-gutters">
|
||||||
>
|
<div className="col-md-4 col-xxl-2 col-md-4">
|
||||||
<i className="fa fa-plus pl-2"></i>
|
<div className="mail-sidebar">
|
||||||
</a>
|
<div className="row justify-content-center">
|
||||||
</div>
|
<div className="d-none col-12">
|
||||||
</div>
|
<div className="text-center mail-sidebar-title px-4">
|
||||||
<div className="col-12">
|
<a
|
||||||
<div className="px-4 py-4">
|
href="#"
|
||||||
<ul className="pl-0">
|
className="btn btn-primary btn-block py-3 font-weight-bold font-18"
|
||||||
<li className="py-2">
|
>
|
||||||
<a href="#">
|
<i className="fa fa-plus pl-2"></i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="col-12">
|
||||||
|
<div className="px-4 py-4">
|
||||||
|
<ul className="pl-0">
|
||||||
|
<li className="py-2">
|
||||||
|
<a href="#">
|
||||||
<span className="nav align-items-center">
|
<span className="nav align-items-center">
|
||||||
<span>
|
<span>
|
||||||
<i className="fa fa-envelope-o text-primary pr-4"></i>
|
<i className="fa fa-envelope-o text-primary pr-4"></i>
|
||||||
@@ -122,84 +122,89 @@ export default function Comments() {
|
|||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{/*<li className="py-2">*/}
|
{/*<li className="py-2">*/}
|
||||||
{/* <a href="#">*/}
|
{/* <a href="#">*/}
|
||||||
{/* <span*/}
|
{/* <span*/}
|
||||||
{/* className="nav align-items-center">*/}
|
{/* className="nav align-items-center">*/}
|
||||||
{/* <span>*/}
|
{/* <span>*/}
|
||||||
{/* <i className="fa fa-paper-plane-o pr-4"></i>*/}
|
{/* <i className="fa fa-paper-plane-o pr-4"></i>*/}
|
||||||
{/* </span>*/}
|
{/* </span>*/}
|
||||||
{/* <span>*/}
|
{/* <span>*/}
|
||||||
{/* <span>Replied Mail</span>*/}
|
{/* <span>Replied Mail</span>*/}
|
||||||
{/* </span>*/}
|
{/* </span>*/}
|
||||||
{/* </span>*/}
|
{/* </span>*/}
|
||||||
{/* </a>*/}
|
{/* </a>*/}
|
||||||
{/*</li>*/}
|
{/*</li>*/}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<ul className="pl-0 mt-5">
|
<ul className="pl-0 mt-5">
|
||||||
<li
|
<li
|
||||||
className="py-2"
|
className="py-2"
|
||||||
onClick={() => changeActiveCategoryUID("0")}
|
onClick={() => changeActiveCategoryUID("0")}
|
||||||
style={{ cursor: "pointer" }}
|
style={{ cursor: "pointer" }}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<span className="nav align-items-center">
|
<span className="nav align-items-center">
|
||||||
<span>
|
<span>
|
||||||
<i
|
<i
|
||||||
className={`fa fa-circle-o pr-4 ${
|
className={`fa fa-circle-o pr-4 ${
|
||||||
activeCategoryUID == "0"
|
activeCategoryUID == "0"
|
||||||
? "text-primary"
|
? "text-primary"
|
||||||
: "text-warning"
|
: "text-warning"
|
||||||
}`}
|
}`}
|
||||||
></i>
|
></i>
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<span>All</span>
|
<span>All</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{contactsCategory &&
|
{contactsCategory &&
|
||||||
contactsCategory.map((item) => (
|
contactsCategory.map((item) => (
|
||||||
<li
|
<li
|
||||||
key={item?.cid}
|
key={item?.cid}
|
||||||
className="py-2"
|
className="py-2"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
changeActiveCategoryUID(`${item?.cid}`)
|
changeActiveCategoryUID(`${item?.cid}`)
|
||||||
}
|
}
|
||||||
style={{ cursor: "pointer" }}
|
style={{ cursor: "pointer" }}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<span className="nav align-items-center">
|
<span className="nav align-items-center">
|
||||||
<span>
|
<span>
|
||||||
<i
|
<i
|
||||||
className={`fa fa-circle-o pr-4 ${
|
className={`fa fa-circle-o pr-4 ${
|
||||||
activeCategoryUID ==
|
activeCategoryUID ==
|
||||||
`${item?.cid}`
|
`${item?.cid}`
|
||||||
? "text-primary"
|
? "text-primary"
|
||||||
: "text-warning"
|
: "text-warning"
|
||||||
}`}
|
}`}
|
||||||
></i>
|
></i>
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<span>{item?.description}</span>
|
<span>{item?.description}</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</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'}}>
|
</div>
|
||||||
{/* <div className="mail-search border-bottom">
|
<div
|
||||||
|
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="row align-items-center mx-0">
|
<div className="row align-items-center mx-0">
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<div className="form-group pt-3">
|
<div className="form-group pt-3">
|
||||||
@@ -209,141 +214,160 @@ export default function Comments() {
|
|||||||
</div>
|
</div>
|
||||||
</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 ||
|
||||||
(!activeContactUID && index == 0);
|
(!activeContactUID && index == 0);
|
||||||
const avtarImage =
|
const avtarImage =
|
||||||
contact?.category === undefined
|
contact?.category === undefined
|
||||||
? "avtar/01.jpg"
|
? "avtar/01.jpg"
|
||||||
: "avtar/" + contact.category + ".png";
|
: "avtar/" + contact.category + ".png";
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={contact?.uid}
|
key={contact?.uid}
|
||||||
onClick={() => changeActiveUID(contact?.uid)}
|
onClick={() => changeActiveUID(contact?.uid)}
|
||||||
className={`mail-msg-item ${
|
className={`mail-msg-item ${
|
||||||
isActive && "bg-light"
|
isActive && "bg-light"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<a href="#">
|
<a href="#">
|
||||||
<div className="media align-items-center">
|
<div className="media align-items-center">
|
||||||
<div className="mr-3">
|
<div className="mr-3">
|
||||||
<div className="bg-img">
|
<div className="bg-img">
|
||||||
<img
|
<img
|
||||||
src={getImage(avtarImage)}
|
src={getImage(avtarImage)}
|
||||||
className="img-fluid"
|
className="img-fluid"
|
||||||
alt="user"
|
alt="user"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-100">
|
<div className="w-100">
|
||||||
<div className="mail-msg-item-titel justify-content-between">
|
<div className="mail-msg-item-titel justify-content-between">
|
||||||
<p>
|
<p>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fontSize: "14px",
|
fontSize: "14px",
|
||||||
color: "#148399",
|
color: "#148399",
|
||||||
fontWeight: "bolder",
|
fontWeight: "bolder",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{contact?.sender}
|
{contact?.sender}
|
||||||
</span>
|
</span>
|
||||||
</p>
|
</p>
|
||||||
{/* <p className="d-none d-xl-block">06:59 <span> PM </span></p> */}
|
{/* <p className="d-none d-xl-block">06:59 <span> PM </span></p> */}
|
||||||
<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>
|
||||||
</div>
|
</div>
|
||||||
<h5 className="mb-0 my-2">
|
<h5 className="mb-0 my-2">
|
||||||
{contact?.title}
|
{contact?.title}
|
||||||
</h5>
|
</h5>
|
||||||
<p>
|
<p>
|
||||||
{contact?.message?.length < 100
|
{contact?.message?.length < 100
|
||||||
? contact?.message
|
? contact?.message
|
||||||
: contact?.message.substring(0, 101) +
|
: contact?.message.substring(0, 101) +
|
||||||
" ..."}
|
" ..."}
|
||||||
</p>
|
</p>
|
||||||
<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>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</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
|
||||||
</div>
|
available for selection
|
||||||
</div>
|
</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{filteredContactData.length > 0 &&
|
|
||||||
<div className="col-xxl-6 border-t border-xxl-t">
|
|
||||||
<div className="mail-chat py-5 px-5">
|
|
||||||
<div className="media align-items-center">
|
|
||||||
<div className="bg-img mr-3">
|
|
||||||
<img
|
|
||||||
src={activeContactUID ? getImage("avtar/" + activeDetail[0].category + ".png") : getImage(filteredContactData[0] == undefined ? "avtar/01.jpg": "avtar/" + filteredContactData[0].category + ".png")}
|
|
||||||
className="img-fluid"
|
|
||||||
alt="user"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<h4 className="mb-0" style={{ color: "#148399" }}>
|
|
||||||
{activeContactUID
|
|
||||||
? activeDetail[0]?.sender
|
|
||||||
: filteredContactData[0]?.sender}
|
|
||||||
</h4>
|
|
||||||
<p>
|
|
||||||
{activeContactUID
|
|
||||||
? new Date(activeDetail[0]?.added).toDateString()
|
|
||||||
: new Date(
|
|
||||||
filteredContactData[0]?.added
|
|
||||||
).toDateString()}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="mt-4 d-flex justify-content-between">
|
|
||||||
<div>
|
|
||||||
<h3>
|
|
||||||
{activeContactUID
|
|
||||||
? activeDetail[0]?.title
|
|
||||||
: filteredContactData[0]?.title}
|
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
<div className="d-flex">
|
|
||||||
{/*<a href="javascript:void(0)"><i className="fa fa-reply font-22 pr-3"></i></a>*/}
|
|
||||||
{/*<a href="javascript:void(0)"><i className="fa fa-print font-22"></i></a>*/}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p>
|
|
||||||
{activeContactUID
|
|
||||||
? activeDetail[0]?.message
|
|
||||||
: filteredContactData[0]?.message}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{filteredContactData.length > 0 && (
|
||||||
|
<div className="col-xxl-6 border-t border-xxl-t">
|
||||||
|
<div className="mail-chat py-5 px-5">
|
||||||
|
<div className="media align-items-center">
|
||||||
|
<div className="bg-img mr-3">
|
||||||
|
<img
|
||||||
|
src={
|
||||||
|
activeContactUID
|
||||||
|
? getImage(
|
||||||
|
"avtar/" +
|
||||||
|
activeDetail[0].category +
|
||||||
|
".png",
|
||||||
|
)
|
||||||
|
: getImage(
|
||||||
|
filteredContactData[0] == undefined
|
||||||
|
? "avtar/01.jpg"
|
||||||
|
: "avtar/" +
|
||||||
|
filteredContactData[0].category +
|
||||||
|
".png",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
className="img-fluid"
|
||||||
|
alt="user"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h4 className="mb-0" style={{ color: "#148399" }}>
|
||||||
|
{activeContactUID
|
||||||
|
? activeDetail[0]?.sender
|
||||||
|
: filteredContactData[0]?.sender}
|
||||||
|
</h4>
|
||||||
|
<p>
|
||||||
|
{activeContactUID
|
||||||
|
? new Date(
|
||||||
|
activeDetail[0]?.added,
|
||||||
|
).toDateString()
|
||||||
|
: new Date(
|
||||||
|
filteredContactData[0]?.added,
|
||||||
|
).toDateString()}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mt-4 d-flex justify-content-between">
|
||||||
|
<div>
|
||||||
|
<h3>
|
||||||
|
{activeContactUID
|
||||||
|
? activeDetail[0]?.title
|
||||||
|
: filteredContactData[0]?.title}
|
||||||
|
</h3>
|
||||||
|
</div>
|
||||||
|
<div className="d-flex">
|
||||||
|
{/*<a href="javascript:void(0)"><i className="fa fa-reply font-22 pr-3"></i></a>*/}
|
||||||
|
{/*<a href="javascript:void(0)"><i className="fa fa-print font-22"></i></a>*/}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p>
|
||||||
|
{activeContactUID
|
||||||
|
? activeDetail[0]?.message
|
||||||
|
: filteredContactData[0]?.message}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
</div>
|
||||||
</>
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,18 +42,34 @@ 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)
|
||||||
queryClient.refetchQueries({
|
if(data?.message_action === socketOnEvents.refresh_all_actions){
|
||||||
queryKey: [...queryKeys.recentAction],
|
queryClient.refetchQueries({
|
||||||
// type: 'active',
|
queryKey: [...queryKeys.recentAction],
|
||||||
// exact: true,
|
// type: 'active',
|
||||||
})
|
// exact: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if(data?.message_action === socketOnEvents.refresh_provision){
|
||||||
|
queryClient.refetchQueries({ // refetches product Page API call
|
||||||
|
queryKey: [...queryKeys.product_page],
|
||||||
|
})
|
||||||
|
queryClient.refetchQueries({ // refetches productProvision API call
|
||||||
|
queryKey: [...queryKeys.myproduct_provision],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on(socketOnEvents.refresh_provision, (data) => {
|
// socket.on(socketOnEvents.refresh_provision, (data) => {
|
||||||
queryClient.refetchQueries({ // refetches productProvision API call
|
// queryClient.refetchQueries({ // refetches productProvision API call
|
||||||
queryKey: [...queryKeys.myproduct_provision],
|
// 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", () => {
|
||||||
|
|||||||
@@ -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`}>
|
{
|
||||||
<Link to={productPath(product?.product_id)} >
|
// let productName = product?.name?.length > 14 ? product?.name?.substring(0, 14) + '...' : product?.name
|
||||||
<div className={`d-flex align-items-center extraProductCard ${product?.icon_style}`} style={{borderColor:'black', borderWidth: '2px'}} >
|
return (
|
||||||
<div className="icon-container img-icon m-r-20 bg-light-gray rounded">
|
<div key={product.uid+index} className={`col-12 col-lg-6 mb-2 mb-xxl-0`}>
|
||||||
<i className={`fa ${product?.product_icon} text-primary`}></i>
|
<Link to={productPath(product?.product_id)} >
|
||||||
|
<div className={`d-flex align-items-center extraProductCard ${product?.icon_style}`} style={{borderColor:'black', borderWidth: '2px'}} >
|
||||||
|
<div className="icon-container img-icon m-r-20 bg-light-gray rounded">
|
||||||
|
<i className={`fa ${product?.product_icon} text-primary`}></i>
|
||||||
|
</div>
|
||||||
|
<div className="report-details overflow-hidden">
|
||||||
|
<p><span style={{fontWeight: 'bolder', color: '#00557A'}}>{product?.status_text}</span></p>
|
||||||
|
<h4><span className='w-100 d-inline-block text-truncate' style={{paddingLeft: '10px'}}>{product?.name}</span></h4>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="report-details">
|
</Link>
|
||||||
<p><span style={{fontWeight: 'bolder', color: '#00557A'}}>{product?.status_text}</span></p>
|
|
||||||
<h4><span className='text-truncate' style={{paddingLeft: '10px'}}>{product?.name}</span></h4>
|
</div>
|
||||||
</div>
|
)
|
||||||
</div>
|
}
|
||||||
</Link>
|
)}
|
||||||
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div className="apexchart-wrapper">
|
<div className="apexchart-wrapper">
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -74,7 +74,11 @@ 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">
|
||||||
|
|||||||
@@ -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" style={{minHeight: '680px'}}>
|
<div className="card-body" style={{minHeight: '600px', maxHeight: '600px'}}>
|
||||||
<iframe ref={iframe} style={{borderWidth: '0px'}} src={externalUrl} width="100%" height="600" title={externalUrl}></iframe>
|
<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">
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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,141 +1,196 @@
|
|||||||
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 = {
|
||||||
|
url: productData?.external_url || "",
|
||||||
|
};
|
||||||
|
|
||||||
const initialValues = {
|
let defaultUrl = "https://" + productData?.internal_url;
|
||||||
url: productData?.external_url || '',
|
let externalUrl = productData?.external_url;
|
||||||
|
|
||||||
|
const handleExternalURLChanged = (e) => {
|
||||||
|
if (e.target.value == externalUrl) {
|
||||||
|
setExternalURLChanged(true);
|
||||||
|
} else {
|
||||||
|
setExternalURLChanged(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// API to set url
|
||||||
|
const setURL = useMutation({
|
||||||
|
mutationFn: (fields) => {
|
||||||
|
return setExternalURL(fields);
|
||||||
|
},
|
||||||
|
onSuccess: (res) => {
|
||||||
|
if (res.data.resultCode != "0") {
|
||||||
|
// throw({message: res?.data?.resultDescription})
|
||||||
|
throw { message: "Something went wrong!" };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onSettled: () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
setURL.reset();
|
||||||
|
}, 3000);
|
||||||
|
},
|
||||||
|
// onError: (err) => {
|
||||||
|
// console.log('err', err)
|
||||||
|
// }
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleSubmit = (values) => {
|
||||||
|
let reqData = {
|
||||||
|
token: localStorage.getItem("token"), // USER TOKEN
|
||||||
|
uid: localStorage.getItem("uid"), // USER UID
|
||||||
|
subscription_uid: productData?.subscription_uid,
|
||||||
|
external_url: values.url,
|
||||||
};
|
};
|
||||||
|
setURL.mutate(reqData);
|
||||||
|
};
|
||||||
|
|
||||||
let defaultUrl = 'https://' + productData?.internal_url
|
return (
|
||||||
let externalUrl = productData?.external_url
|
<>
|
||||||
|
<div className="card card-statistics">
|
||||||
const handleExternalURLChanged = (e) => {
|
<div className="card-header">
|
||||||
if(e.target.value == externalUrl){
|
<div className="card-heading">
|
||||||
setExternalURLChanged(true)
|
<h4 className="card-title" style={{ textTransform: "none" }}>
|
||||||
}else{
|
{defaultUrl}
|
||||||
setExternalURLChanged(false)
|
</h4>
|
||||||
}
|
</div>
|
||||||
}
|
|
||||||
|
|
||||||
// API to set url
|
|
||||||
const setURL = useMutation({
|
|
||||||
mutationFn: (fields) => {
|
|
||||||
return setExternalURL(fields)
|
|
||||||
},
|
|
||||||
onSuccess: (res) => {
|
|
||||||
if (res.data.resultCode != '0') {
|
|
||||||
// throw({message: res?.data?.resultDescription})
|
|
||||||
throw({message: 'Something went wrong!'})
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onSettled: () => {
|
|
||||||
setTimeout(() => {
|
|
||||||
setURL.reset()
|
|
||||||
}, 3000)
|
|
||||||
}
|
|
||||||
// onError: (err) => {
|
|
||||||
// console.log('err', err)
|
|
||||||
// }
|
|
||||||
})
|
|
||||||
|
|
||||||
const handleSubmit = (values) => {
|
|
||||||
let reqData = {
|
|
||||||
token: localStorage.getItem('token'), // USER TOKEN
|
|
||||||
uid: localStorage.getItem('uid'), // USER UID
|
|
||||||
subscription_uid: productData?.subscription_uid,
|
|
||||||
external_url: values.url
|
|
||||||
}
|
|
||||||
setURL.mutate(reqData)
|
|
||||||
}
|
|
||||||
|
|
||||||
return <>
|
|
||||||
<div className="card card-statistics">
|
|
||||||
<div className="card-header">
|
|
||||||
<div className="card-heading">
|
|
||||||
<h4 className="card-title" style={{textTransform: 'none'}}>{defaultUrl}</h4>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/*<div className="card-body">*/}
|
|
||||||
{/* <div className="form-group">*/}
|
|
||||||
{/* /!*<label htmlFor="exampleInputEmail1">Email address</label>*!/*/}
|
|
||||||
{/* <input type="email" className="form-control"*/}
|
|
||||||
{/* aria-describedby="defaultUrlHelp" value={defaultUrl} readOnly={true} />*/}
|
|
||||||
{/* </div>*/}
|
|
||||||
{/*</div>*/}
|
|
||||||
</div>
|
</div>
|
||||||
|
{/*<div className="card-body">*/}
|
||||||
|
{/* <div className="form-group">*/}
|
||||||
|
{/* /!*<label htmlFor="exampleInputEmail1">Email address</label>*!/*/}
|
||||||
|
{/* <input type="email" className="form-control"*/}
|
||||||
|
{/* aria-describedby="defaultUrlHelp" value={defaultUrl} readOnly={true} />*/}
|
||||||
|
{/* </div>*/}
|
||||||
|
{/*</div>*/}
|
||||||
|
</div>
|
||||||
|
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
validationSchema={validationSchema}
|
validationSchema={validationSchema}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
>
|
>
|
||||||
{(props) => {
|
{(props) => {
|
||||||
return (
|
return (
|
||||||
<Form className='w-full'>
|
<Form className="w-full">
|
||||||
<div className="card card-statistics" style={{backgroundColor: '#b6e5ef'}}>
|
<div
|
||||||
<div className="card-header">
|
className="card card-statistics"
|
||||||
<div className="card-heading">
|
style={{ backgroundColor: "#b6e5ef" }}
|
||||||
<h4 className="card-title" style={{textTransform: 'none'}}>Set your own URL</h4>
|
>
|
||||||
</div>
|
<div className="card-header">
|
||||||
</div>
|
<div className="card-heading">
|
||||||
<div className="card-body">
|
<h4
|
||||||
<div className="form-group">
|
className="card-title"
|
||||||
<label htmlFor="exampleInputEmail1">Enter your full URL <span
|
style={{ textTransform: "none" }}
|
||||||
className={`${(props.errors.url && props.touched.url) && 'text-danger'}`}>{props.errors.url}</span></label>
|
>
|
||||||
<input value={props.values.url} onChange={(e)=>{props.handleChange(e); handleExternalURLChanged(e)}} type="text"
|
Set your own URL
|
||||||
className="form-control" id="url" aria-describedby="url"
|
</h4>
|
||||||
placeholder="https://example.mysite.com"/>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{width: '100%', textAlign: 'right'}}>
|
<div className="card-body">
|
||||||
<button
|
<div className="form-group">
|
||||||
type="submit"
|
<label htmlFor="exampleInputEmail1">
|
||||||
disabled={setURL.isPending || externalURLChanged}
|
Enter your full URL{" "}
|
||||||
className="btn btn-primary"
|
<span
|
||||||
>
|
className={`${props.errors.url && props.touched.url && "text-danger"}`}
|
||||||
{setURL.isPending ? 'Loading...' : 'Submit'}
|
>
|
||||||
</button>
|
{props.errors.url}
|
||||||
</div>
|
</span>
|
||||||
</div>
|
</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 style={{ width: "100%", textAlign: "right" }}>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
disabled={setURL.isPending || externalURLChanged}
|
||||||
|
className="btn btn-primary"
|
||||||
|
>
|
||||||
|
{setURL.isPending ? "Loading..." : "Submit"}
|
||||||
|
</button>
|
||||||
|
</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 &&
|
|
||||||
<div className="col-12">
|
|
||||||
<p className='text-success'>{'Completed successfully'}</p>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
<div style={{backgroundColor: '#94b8c0', borderRadius: '10px', padding: '10px'}}>
|
|
||||||
Final steps to configure your URL:<br/>
|
|
||||||
DNS:<br/>
|
|
||||||
DNS:<br/>
|
|
||||||
DNS:<br/>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Form>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</Formik>
|
|
||||||
|
|
||||||
|
{setURL.isSuccess && (
|
||||||
|
<div className="col-12">
|
||||||
|
<p className="text-success">{"Completed successfully"}</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
backgroundColor: "#148399",
|
||||||
|
borderRadius: "10px",
|
||||||
|
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>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</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,62 +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() {
|
||||||
|
|
||||||
return(
|
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 (
|
||||||
<>
|
<>
|
||||||
<BreadcrumbComBS title='Reports' paths={['Dashboard', 'Reports']} />
|
<BreadcrumbComBS title='Reports' paths={['Dashboard', 'Reports']}/>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
|
{isFetching ?
|
||||||
|
<>
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-mute'>Loading...</p>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
: isError ?
|
||||||
|
<div className="col-12">
|
||||||
|
<p className='text-danger'>{error?.message}</p>
|
||||||
|
</div>
|
||||||
|
:
|
||||||
|
<div>
|
||||||
<div>
|
<div>
|
||||||
|
<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>
|
||||||
|
|
||||||
<div>
|
{/* <!-- Tab Content --> */}
|
||||||
|
{/* <div className="tab-content">
|
||||||
<div className="card card-statistics" style={{minHeight:'550px'}}>
|
{sortedReportTopicList && sortedReportTopicList.map((item, index) => {
|
||||||
{/*<div className="card-header">*/}
|
return (
|
||||||
{/* <div className="card-heading">*/}
|
<div key={index} className={`tab-pane fade show ${index == 0 && 'active'}`} id={`content-${item?.url}`} role="tabpanel" style={{minHeight: '400px'}}>
|
||||||
{/* <h4 className="card-title"> Tab vertical </h4>*/}
|
{renderedTable[item?.url]}
|
||||||
{/* </div>*/}
|
</div>
|
||||||
{/*</div>*/}
|
)
|
||||||
<div className="card-body">
|
})}
|
||||||
<div className="tab tab-vertical">
|
</div> */}
|
||||||
<ul className="nav nav-tabs" role="tablist">
|
<div className="tab-content">
|
||||||
<li className="nav-item">
|
<div className={`tab-pane fade show active`} style={{minHeight: '400px'}}>
|
||||||
<a className="nav-link active show" id="home-09-tab" data-toggle="tab" href="#home-09" role="tab" aria-controls="home-09" aria-selected="true"> Home</a>
|
{renderedTable[activeTab]}
|
||||||
</li>
|
|
||||||
<li className="nav-item">
|
|
||||||
<a className="nav-link" id="profile-09-tab" data-toggle="tab" href="#profile-09" role="tab" aria-controls="profile-09" aria-selected="false"> Profile </a>
|
|
||||||
</li>
|
|
||||||
<li className="nav-item">
|
|
||||||
<a className="nav-link" id="portfolio-09-tab" data-toggle="tab" href="#portfolio-09" role="tab" aria-controls="portfolio-09" aria-selected="false">Portfolio </a>
|
|
||||||
</li>
|
|
||||||
<li className="nav-item">
|
|
||||||
<a className="nav-link" id="contact-09-tab" data-toggle="tab" href="#contact-09" role="tab" aria-controls="contact-09" aria-selected="false"> Contact </a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div className="tab-content">
|
|
||||||
<div className="tab-pane fade active show" id="home-09" role="tabpanel" aria-labelledby="home-09-tab">
|
|
||||||
<p>Positive pleasure-oriented goals are much more powerful motivators than negative fear-based ones. Although each is successful separately, the right combination of both is the most powerful motivational force known to humankind.Make a list of your achievements toward your long-term goal and remind yourself that intentions don’t count, only action’s.</p>
|
|
||||||
</div>
|
|
||||||
<div className="tab-pane fade" id="profile-09" role="tabpanel" aria-labelledby="profile-09-tab">
|
|
||||||
<p>Reflect and experiment until you find the right combination of motivators for your personality and your personal goals. Do it today. Remind yourself of someone you know who died suddenly and the fact that there is no guarantee that tomorrow will come.</p>
|
|
||||||
</div>
|
|
||||||
<div className="tab-pane fade" id="portfolio-09" role="tabpanel" aria-labelledby="portfolio-09-tab">
|
|
||||||
<p>Commitment is something that comes from understanding that everything has its price and then having the willingness to pay that price. This is important because nobody wants to put significant effort into something, only to find out after the fact that the price was too high. We all know people who live this truth.Give yourself the power of responsibility.</p>
|
|
||||||
</div>
|
|
||||||
<div className="tab-pane fade" id="contact-09" role="tabpanel" aria-labelledby="contact-09-tab">
|
|
||||||
<p>I truly believe Augustine’s words are true and if you look at history you know it is true. There are many people in the world with amazing talents who realize only a small percentage of their potential. We all know people who live this truth.Give yourself the power of responsibility. Remind yourself the only thing stopping you is yourself.</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -8,12 +8,12 @@ import queryKeys from '../../services/queryKeys';
|
|||||||
|
|
||||||
|
|
||||||
const linksValidationSchema = Yup.object().shape({
|
const linksValidationSchema = Yup.object().shape({
|
||||||
// facebook_url: Yup.string().required("facebook is required"),
|
facebook_url: Yup.string().matches(/^https:\/\/.+/,"URL must start with https://"),
|
||||||
// twitter_url: Yup.string().required("twitter is required"),
|
twitter_url: Yup.string().matches(/^https:\/\/.+/,"URL must start with https://"),
|
||||||
// blogger_url: Yup.string().required("blog is required"),
|
blogger_url: Yup.string().matches(/^https:\/\/.+/,"URL must start with https://"),
|
||||||
// google_url: Yup.string().required("google is required"),
|
google_url: Yup.string().matches(/^https:\/\/.+/,"URL must start with https://"),
|
||||||
// linked_url: Yup.string().required("linkedin is required"),
|
linked_url: Yup.string().matches(/^https:\/\/.+/,"URL must start with https://"),
|
||||||
// website_url: Yup.string().required("website is required"),
|
website_url: Yup.string().matches(/^https:\/\/.+/,"URL must start with https://"),
|
||||||
})
|
})
|
||||||
|
|
||||||
export default function LinksForm({data}) {
|
export default function LinksForm({data}) {
|
||||||
@@ -73,10 +73,10 @@ export default function LinksForm({data}) {
|
|||||||
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
|
||||||
...infoToUpdate
|
url_list: {...infoToUpdate}
|
||||||
}
|
}
|
||||||
console.log(reqData)
|
// console.log(reqData)
|
||||||
// updateLinksMutation.mutate(reqData)
|
updateLinksMutation.mutate(reqData)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -90,31 +90,31 @@ export default function LinksForm({data}) {
|
|||||||
return (
|
return (
|
||||||
<Form className=''>
|
<Form className=''>
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label htmlFor="fb">Facebook URL: {(props.errors.facebook_url && props.touched.facebook_url) && <span className="text-danger">*</span>}</label>
|
<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} />
|
<input type="text" className="form-control" name="facebook_url" value={props.values?.facebook_url} onChange={props.handleChange} />
|
||||||
</div>
|
</div>
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label htmlFor="tr">Twitter URL: {(props.errors.twitter_url && props.touched.twitter_url) && <span className="text-danger">*</span>}</label>
|
<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} />
|
<input type="text" className="form-control" name="twitter_url" value={props.values?.twitter_url} onChange={props.handleChange} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label htmlFor="br">Blogger URL: {(props.errors.blogger_url && props.touched.blogger_url) && <span className="text-danger">*</span>}</label>
|
<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} />
|
<input type="text" className="form-control" name="blogger_url" value={props.values?.blogger_url} onChange={props.handleChange} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label htmlFor="go">Google+ URL: {(props.errors.google_url && props.touched.google_url) && <span className="text-danger">*</span>}</label>
|
<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} />
|
<input type="text" className="form-control" name="google_url" value={props.values?.google_url} onChange={props.handleChange} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label htmlFor="li">LinkedIn URL: {(props.errors.linked_url && props.touched.linked_url) && <span className="text-danger">*</span>}</label>
|
<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} />
|
<input type="text" className="form-control" name="linked_url" value={props.values?.linked_url} onChange={props.handleChange} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label htmlFor="we">Website URL: {(props.errors.website_url && props.touched.website_url) && <span className="text-danger">*</span>}</label>
|
<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} />
|
<input type="text" className="form-control" name="website_url" value={props.values?.website_url} onChange={props.handleChange} />
|
||||||
</div>
|
</div>
|
||||||
<div style={{textAlign: "right"}}>
|
<div style={{textAlign: "right"}}>
|
||||||
@@ -137,7 +137,7 @@ export default function LinksForm({data}) {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="modal-body">
|
<div className="modal-body">
|
||||||
<h5 className="text-center" style={{fontSize: '18px'}}>Are you sure, you want to update? gg</h5>
|
<h5 className="text-center" style={{fontSize: '18px'}}>Are you sure, you want to update?</h5>
|
||||||
{(updateLinksMutation.error || updateLinksMutation.isSuccess) && (
|
{(updateLinksMutation.error || updateLinksMutation.isSuccess) && (
|
||||||
<div className="col-12">
|
<div className="col-12">
|
||||||
<p className={`p-2 text-center ${updateLinksMutation.isSuccess ? 'text-success' : 'text-danger'}`}>
|
<p className={`p-2 text-center ${updateLinksMutation.isSuccess ? 'text-success' : 'text-danger'}`}>
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export default function ProfileForm({data}) {
|
|||||||
},
|
},
|
||||||
onSuccess: (res) => {
|
onSuccess: (res) => {
|
||||||
if(res.data.resultCode != '0'){
|
if(res.data.resultCode != '0'){
|
||||||
throw({message: res?.data?.resultDescription ? res?.data?.resultDescription : 'En error occured'})
|
throw({message: res?.data?.resultDescription ? res?.data?.resultDescription : 'An error occured'})
|
||||||
}
|
}
|
||||||
const account_name = res?.data?.personal_data?.account_name
|
const account_name = res?.data?.personal_data?.account_name
|
||||||
dispatch(updateUserDetails({ account_name }));
|
dispatch(updateUserDetails({ account_name }));
|
||||||
@@ -72,6 +72,7 @@ export default function ProfileForm({data}) {
|
|||||||
const handleSetInfoToUpdate = (values, helpers) => {
|
const handleSetInfoToUpdate = (values, helpers) => {
|
||||||
delete values.email
|
delete values.email
|
||||||
delete values.country
|
delete values.country
|
||||||
|
delete values?.picture
|
||||||
setInfoToUpdate(values)
|
setInfoToUpdate(values)
|
||||||
var modal = new Modal(document.getElementById('modal'));
|
var modal = new Modal(document.getElementById('modal'));
|
||||||
modal.show();
|
modal.show();
|
||||||
|
|||||||
@@ -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,14 +1,14 @@
|
|||||||
import React, { useMemo, useState } from "react";
|
import React, { useMemo, useState } from "react";
|
||||||
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 ProfileForm from "./ProfileForm";
|
||||||
import LinksForm from "./LinksForm";
|
import LinksForm from "./LinksForm";
|
||||||
|
import ProfileImage from "./ProfileImage";
|
||||||
|
|
||||||
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: {},
|
||||||
@@ -59,36 +59,7 @@ 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">
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export default function Subscription() {
|
|||||||
<h2 className="text-primary pt-3">{currentSubscription?.display_name}</h2>
|
<h2 className="text-primary pt-3">{currentSubscription?.display_name}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="pt-2" style={{textAlign: 'left'}}>
|
<div className="pt-2" style={{textAlign: 'left'}}>
|
||||||
<div style={{fontSize: '12px', fontWeight: 'bolder' , color: "#3E3699" }}>
|
<div style={{fontSize: '12px', fontWeight: 'bolder', color: "#3E3699"}}>
|
||||||
Next Payment: {getDateTimeFromDateString(currentSubscription?.next_payment)}
|
Next Payment: {getDateTimeFromDateString(currentSubscription?.next_payment)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
function sortArrayByListOrder(data) {
|
||||||
|
// Convert object to array if needed
|
||||||
|
const array = Array.isArray(data)
|
||||||
|
? [...data]
|
||||||
|
: Object.values(data);
|
||||||
|
|
||||||
|
// Sort ascending by list_order
|
||||||
|
array.sort((a, b) => {
|
||||||
|
const orderA = a.list_order ?? 0;
|
||||||
|
const orderB = b.list_order ?? 0;
|
||||||
|
return orderA - orderB;
|
||||||
|
});
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default sortArrayByListOrder
|
||||||
@@ -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'],
|
||||||
|
|||||||
@@ -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 => {
|
||||||
// throw new Error(err.response.data.error_message);
|
throw new Error(err.response.data.error_message);
|
||||||
throw new Error(err);
|
// throw new Error(err);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +105,7 @@ export const updateLinks = (reqData) => {
|
|||||||
let postData = {
|
let postData = {
|
||||||
...reqData,
|
...reqData,
|
||||||
}
|
}
|
||||||
return null //postAuxEnd(`/panel/account/links-update`, postData, false)
|
return postAuxEnd(`/panel/account/profilelinks-update`, postData, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION TO GET PRODUCT BY ID
|
// FUNCTION TO GET PRODUCT BY ID
|
||||||
@@ -236,6 +244,14 @@ export const getProductColorStyles = (reqData) => {
|
|||||||
}
|
}
|
||||||
return postAuxEnd(`/panel/account/products/color-styles`, postData, false)
|
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 = {
|
||||||
@@ -268,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 = {
|
||||||
@@ -284,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