Compare commits

..

57 Commits

Author SHA1 Message Date
ameye 47d3bded9d style changes 2026-05-23 10:08:05 -04:00
ameye 22c7182993 StripeSubscriptionButton 2026-05-23 09:15:37 -04:00
CHIEFSOFT\ameye 29a2c937fe removed Subscription 2026-05-23 08:35:50 -04:00
CHIEFSOFT\ameye 3a81da3713 removed Subscription 2026-05-23 08:24:59 -04:00
ameye 4ace1acda3 inform before charges 2026-05-23 08:20:18 -04:00
CHIEFSOFT\ameye 04afae48a2 removed Subscription 2026-05-23 07:48:18 -04:00
CHIEFSOFT\ameye 1a35a8c9b8 removed Subscription 2026-05-23 07:37:31 -04:00
ameye 4f3fb44fcd Merge branch 'bug-fix' of MERMS/MermsPanelReactJS into master 2026-05-20 20:02:01 +00:00
victorAnumudu ef24f269dc refresh provisioning bug fixed 2026-05-20 18:14:00 +01:00
ameye 51df8293c3 Merge branch 'socket-provision-refresh' of MERMS/MermsPanelReactJS into master 2026-05-19 21:52:35 +00:00
victorAnumudu 546b6177dc made product page to reload on when provision is done 2026-05-19 18:20:10 +01:00
ameye db116f36e3 Merge branch 'img-list-width-adjust' of MERMS/MermsPanelReactJS into master 2026-05-18 17:27:24 +00:00
victorAnumudu 4f93c5b2c2 img list width adjusted 2026-05-18 18:25:49 +01:00
ameye 0a3ca0234e Merge branch 'captcha-centering' of MERMS/MermsPanelReactJS into master 2026-05-18 17:05:50 +00:00
victorAnumudu a88da5cf0e centralized captcha section 2026-05-18 17:12:00 +01:00
CHIEFSOFT\ameye 159f1fcdc8 Added report starter 2026-05-16 17:31:48 -04:00
CHIEFSOFT\ameye f50df99417 Email is required 2026-05-16 04:53:23 -04:00
CHIEFSOFT\ameye 9217e88831 Turnstile 2026-05-16 04:26:50 -04:00
CHIEFSOFT\ameye 49c6c6afe9 turnstile 2026-05-16 03:59:39 -04:00
CHIEFSOFT\ameye ffd00155e0 REACT_APP_TURNSTILE_SITE_KEY 2026-05-16 03:23:36 -04:00
CHIEFSOFT\ameye 9fd3636ffd NEXT_SITE_SECURITY_KEY 2026-05-16 03:14:41 -04:00
CHIEFSOFT\ameye 5ff6b4a4d2 NEXT_SITE_SECURITY_KEY 2026-05-16 03:08:05 -04:00
CHIEFSOFT\ameye 22c431c8e0 Turnstile 2026-05-16 02:47:51 -04:00
ameye 2db3a4d6f4 Merge branch 'picture-payload-removal' of MERMS/MermsPanelReactJS into master 2026-05-14 17:11:06 +00:00
victorAnumudu 1310561e55 removed picture payload from the update profile endpoint 2026-05-14 18:00:04 +01:00
ameye edcb6cac7d Merge branch 'login-bug-fix' of MERMS/MermsPanelReactJS into master 2026-05-11 17:13:11 +00:00
victorAnumudu be8460c20b login bug fixed 2026-05-11 18:08:43 +01:00
ameye 0794dfb8e0 templAte fix 2026-05-03 13:55:52 -04:00
ameye d950988e62 Clean code 2026-04-26 14:22:19 -04:00
ameye 295473d416 Commnented Image 2026-04-26 14:19:47 -04:00
ameye acc2c6eab4 comment fixed node version 2026-04-26 04:50:01 -04:00
ameye 9f6db5d13d removed yarn 2026-04-26 03:42:26 -04:00
ameye 71e66d3783 FROM alpine:3.22 2026-04-26 03:32:14 -04:00
ameye 2c7085b04b Fix messages 2026-04-26 03:14:54 -04:00
ameye 2c7584c00f Merge branch 'signup-endpoint-fix' of MERMS/MermsPanelReactJS into master 2026-04-22 21:35:50 +00:00
victorAnumudu 4d00178d94 signup endpoint bug fixed 2026-04-22 18:19:54 +01:00
tokslaw 863da32f93 Merge branch 'link-with-https' of MERMS/MermsPanelReactJS into master 2026-03-21 16:53:52 +00:00
tokslaw b9ad9e922e link added to terms conditions and privacy 2026-03-21 12:42:37 -04:00
victorAnumudu 5ad75e412b https validator added 2026-02-25 19:49:31 +01:00
ameye e9d6689418 Merge branch 'link-update-validation-removed' of MERMS/MermsPanelReactJS into master 2026-02-25 07:46:25 +00:00
victorAnumudu ed38e0db98 made update link params optional 2026-02-24 09:18:06 +01:00
ameye 351f027a6f Merge branch 'payment-table-update' of MERMS/MermsPanelReactJS into master 2026-02-23 22:50:07 +00:00
victorAnumudu 20d56ee307 payment table updated 2026-02-23 19:14:36 +01:00
ameye f5c798c6c1 Merge branch 'header-profile-image' of MERMS/MermsPanelReactJS into master 2026-02-16 11:27:02 +00:00
victorAnumudu a11f5100ba header profile image bug fixed 2026-02-16 11:32:16 +01:00
CHIEFSOFT\ameye 7628a561f8 Merge branch 'master' of https://gitlab.chiefsoft.net/MERMS/MermsPanelReactJS 2026-02-15 17:33:56 -05:00
CHIEFSOFT\ameye 615acff0b7 fixed reports 2026-02-15 17:33:34 -05:00
ameye aea161ccaf Merge branch 'profile-picture-upload' of MERMS/MermsPanelReactJS into master 2026-02-14 11:00:42 +00:00
victorAnumudu 66a2bcacd5 profile image upload added 2026-02-10 18:17:44 +01:00
ameye ec9d84b779 Merge branch 'truncating-text' of MERMS/MermsPanelReactJS into master 2026-02-10 17:00:38 +00:00
victorAnumudu 8ee793d11e text truncated 2026-02-09 19:11:17 +01:00
ameye 46f17cbdfe Merge branch 'template-payload-fix' of MERMS/MermsPanelReactJS into master 2026-01-21 09:45:48 +00:00
victorAnumudu 283994e43a pauload fixed 2026-01-21 10:25:56 +01:00
ameye b7d242ff0a Merge branch 'template-media-set' of MERMS/MermsPanelReactJS into master 2026-01-21 08:44:57 +00:00
victorAnumudu f6bae30bdd btn name changed 2026-01-21 04:19:05 +01:00
victorAnumudu a7e2e865de added template media set endpoint 2026-01-21 03:27:48 +01:00
ameye 51887cf0d6 Merge branch 'upload-btn-bug' of MERMS/MermsPanelReactJS into master 2026-01-20 17:11:43 +00:00
37 changed files with 13350 additions and 6934 deletions
+8
View File
@@ -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
+7
View File
@@ -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
+8
View File
@@ -18,3 +18,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://www.mermsemr.com/info/dns'
#CLOUDFLARE
REACT_APP_TURNSTILE_SITE_KEY=0x4AAAAAADQV82wuocFR-u5O
+8
View File
@@ -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
+4 -4
View File
@@ -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
View File
@@ -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 ./
+10181 -3715
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -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",
+1 -1
View File
@@ -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){
+17 -5
View File
@@ -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>
</> </>
: :
+18 -7
View File
@@ -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>
+20 -2
View File
@@ -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>
</> </>
+40 -16
View File
@@ -2,10 +2,10 @@
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS"; import BreadcrumbComBS from "../breadcrumb/BreadcrumbComBS";
import getImage from "../../utils/getImage"; import getImage from "../../utils/getImage";
import { useMutation, useQuery } from "@tanstack/react-query"; import { useMutation } from "@tanstack/react-query";
import { commentsData } from "../../services/services"; import { commentsData } from "../../services/services";
import queryKeys from "../../services/queryKeys"; // import queryKeys from "../../services/queryKeys";
import getCustomTime from "../../utils/getCustomTime"; // import getCustomTime from "../../utils/getCustomTime";
export default function Comments() { export default function Comments() {
// const {data:contacts, isFetching, isError, error} = useQuery({ // const {data:contacts, isFetching, isError, error} = useQuery({
@@ -197,8 +197,13 @@ export default function Comments() {
</div> </div>
</div> </div>
</div> </div>
<div className={`${filteredContactData.length > 0 ? 'col-md-8 col-xxl-4' : 'col-md-8 col-xxl-10'} border-md-t`}> <div
<div className="mail-content border-right border-n h-100" style={{placeContent: 'center'}}> className={`${filteredContactData.length > 0 ? "col-md-8 col-xxl-4" : "col-md-8 col-xxl-10"} border-md-t`}
>
<div
className="mail-content border-right border-n h-100"
style={{ placeContent: "center" }}
>
{/* <div className="mail-search border-bottom"> {/* <div className="mail-search border-bottom">
<div className="row align-items-center mx-0"> <div className="row align-items-center mx-0">
<div className="col-12"> <div className="col-12">
@@ -210,7 +215,7 @@ export default function Comments() {
</div> </div>
</div> */} </div> */}
<div className="mail-msg scrollbar scroll_dark"> <div className="mail-msg scrollbar scroll_dark">
{ filteredContactData.length ? {filteredContactData.length ? (
filteredContactData?.map((contact, index) => { filteredContactData?.map((contact, index) => {
const isActive = const isActive =
contact?.uid == activeContactUID || contact?.uid == activeContactUID ||
@@ -255,7 +260,7 @@ export default function Comments() {
<p className="d-none d-xl-block"> <p className="d-none d-xl-block">
<span style={{ fontSize: "14px" }}> <span style={{ fontSize: "14px" }}>
{new Date( {new Date(
contact?.added contact?.added,
).toDateString()} ).toDateString()}
</span> </span>
</p> </p>
@@ -272,7 +277,7 @@ export default function Comments() {
<p className="d-xl-none"> <p className="d-xl-none">
<span> <span>
{new Date( {new Date(
contact?.added contact?.added,
).toDateString()} ).toDateString()}
{/* {getCustomTime(contact.added)} */} {/* {getCustomTime(contact.added)} */}
</span> </span>
@@ -283,19 +288,36 @@ export default function Comments() {
</div> </div>
); );
}) })
: ) : (
<p className="text-center">Messages will appear here as soon as they are available for selection</p> <p className="text-center">
} Messages will appear here as soon as they are
available for selection
</p>
)}
</div> </div>
</div> </div>
</div> </div>
{filteredContactData.length > 0 && {filteredContactData.length > 0 && (
<div className="col-xxl-6 border-t border-xxl-t"> <div className="col-xxl-6 border-t border-xxl-t">
<div className="mail-chat py-5 px-5"> <div className="mail-chat py-5 px-5">
<div className="media align-items-center"> <div className="media align-items-center">
<div className="bg-img mr-3"> <div className="bg-img mr-3">
<img <img
src={activeContactUID ? getImage("avtar/" + activeDetail[0].category + ".png") : getImage(filteredContactData[0] == undefined ? "avtar/01.jpg": "avtar/" + filteredContactData[0].category + ".png")} src={
activeContactUID
? getImage(
"avtar/" +
activeDetail[0].category +
".png",
)
: getImage(
filteredContactData[0] == undefined
? "avtar/01.jpg"
: "avtar/" +
filteredContactData[0].category +
".png",
)
}
className="img-fluid" className="img-fluid"
alt="user" alt="user"
/> />
@@ -308,9 +330,11 @@ export default function Comments() {
</h4> </h4>
<p> <p>
{activeContactUID {activeContactUID
? new Date(activeDetail[0]?.added).toDateString() ? new Date(
activeDetail[0]?.added,
).toDateString()
: new Date( : new Date(
filteredContactData[0]?.added filteredContactData[0]?.added,
).toDateString()} ).toDateString()}
</p> </p>
</div> </div>
@@ -337,7 +361,7 @@ export default function Comments() {
</div> </div>
</div> </div>
</div> </div>
} )}
</div> </div>
</div> </div>
</div> </div>
+19 -3
View File
@@ -42,19 +42,35 @@ export default function SocketIOContextProvider({children}) {
// setSocketMsgReceived(data.message); // setSocketMsgReceived(data.message);
// dispatch(tableReload({type:'CHATMESSAGELIST'})) // dispatches to update chat message sending from owner to worker and vice versa // dispatch(tableReload({type:'CHATMESSAGELIST'})) // dispatches to update chat message sending from owner to worker and vice versa
console.log('SOCKET RECEIVED DATA *** ', data) console.log('SOCKET RECEIVED DATA *** ', data)
if(data?.message_action === socketOnEvents.refresh_all_actions){
queryClient.refetchQueries({ queryClient.refetchQueries({
queryKey: [...queryKeys.recentAction], queryKey: [...queryKeys.recentAction],
// type: 'active', // type: 'active',
// exact: true, // exact: true,
}) })
}); }
if(data?.message_action === socketOnEvents.refresh_provision){
socket.on(socketOnEvents.refresh_provision, (data) => { queryClient.refetchQueries({ // refetches product Page API call
queryKey: [...queryKeys.product_page],
})
queryClient.refetchQueries({ // refetches productProvision API call queryClient.refetchQueries({ // refetches productProvision API call
queryKey: [...queryKeys.myproduct_provision], queryKey: [...queryKeys.myproduct_provision],
}) })
}
}); });
// socket.on(socketOnEvents.refresh_provision, (data) => {
// queryClient.refetchQueries({ // refetches productProvision API call
// queryKey: [...queryKeys.myproduct_provision],
// })
// // queryClient.invalidateQueries({ queryKey: [...queryKeys.product_page] })
// queryClient.refetchQueries({ // refetches product Page API call
// queryKey: [...queryKeys.product_page],
// })
// console.log('SOCKET RECEIVED DATA *** 111 ', data)
// });
// client-side // client-side
socket.on("connect", () => { socket.on("connect", () => {
console.log(socket.id); console.log(socket.id);
+1
View File
@@ -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'
} }
+11 -6
View File
@@ -41,22 +41,27 @@ export default function Products() {
</div> </div>
: :
<div className="row m-b-20"> <div className="row m-b-20">
{products && products.map((product, index) => ( {products && products.map((product, index) =>
<div key={product.uid+index} className={`col-xxs-6 col-xl-4 col-xxl-6 mb-2 mb-xxl-0`}> {
// let productName = product?.name?.length > 14 ? product?.name?.substring(0, 14) + '...' : product?.name
return (
<div key={product.uid+index} className={`col-12 col-lg-6 mb-2 mb-xxl-0`}>
<Link to={productPath(product?.product_id)} > <Link to={productPath(product?.product_id)} >
<div className={`d-flex align-items-center extraProductCard ${product?.icon_style}`} style={{borderColor:'black', borderWidth: '2px'}} > <div className={`d-flex align-items-center extraProductCard ${product?.icon_style}`} style={{borderColor:'black', borderWidth: '2px', paddingLeft:"1px"}} >
<div className="icon-container img-icon m-r-20 bg-light-gray rounded"> <div className="icon-container img-icon m-r-20 bg-light-gray rounded">
<i className={`fa ${product?.product_icon} text-primary`}></i> <i className={`fa ${product?.product_icon} text-primary`}></i>
</div> </div>
<div className="report-details"> <div className="report-details overflow-hidden">
<p><span style={{fontWeight: 'bolder', color: '#00557A'}}>{product?.status_text}</span></p> <p><span style={{fontWeight: 'bolder', color: '#00557A'}}>{product?.status_text}</span></p>
<h4><span className='text-truncate' style={{paddingLeft: '10px'}}>{product?.name}</span></h4> <h4><span className='w-100 d-inline-block text-truncate' style={{paddingLeft: '10px'}}>{product?.name}</span></h4>
</div> </div>
</div> </div>
</Link> </Link>
</div> </div>
))} )
}
)}
</div> </div>
} }
<div className="apexchart-wrapper"> <div className="apexchart-wrapper">
@@ -11,7 +11,7 @@ export default function UserFooter(){
<p>&copy; Copyright {year}. All rights reserved.</p> <p>&copy; 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 autoMedSys A.I.</p> <p>A division of MERMS(AI)</p>
</div> </div>
</div> </div>
</footer> </footer>
+16 -10
View File
@@ -15,7 +15,7 @@ export default function MyMedia() {
const [selectedFile, setSelectedFile] = useState(null); const [selectedFile, setSelectedFile] = useState(null);
const [message, setMessage] = useState(''); const [message, setMessage] = useState('');
const [imageLink, setImageLink] = useState('') const [imageLink, setImageLink] = useState('')
console.log('imageLink', imageLink) console.log('imageLink', imageLink)
// Function to handle file selection // Function to handle file selection
const handleFileChange = (event) => { const handleFileChange = (event) => {
setSelectedFile(event.target.files[0]); setSelectedFile(event.target.files[0]);
@@ -62,7 +62,7 @@ console.log('imageLink', imageLink)
const uploadFileMutation = useMutation({ const uploadFileMutation = useMutation({
mutationFn: (fields) => { mutationFn: (fields) => {
if(!fields.file){ if (!fields.file) {
throw({message: 'Please select a file first!'}) throw({message: 'Please select a file first!'})
} }
return uploadFile(fields) return uploadFile(fields)
@@ -80,7 +80,7 @@ console.log('imageLink', imageLink)
}) })
}, },
onSettled: () => { onSettled: () => {
setTimeout(()=>{ setTimeout(() => {
uploadFileMutation.reset() uploadFileMutation.reset()
}, 3000) }, 3000)
} }
@@ -141,7 +141,8 @@ console.log('imageLink', imageLink)
<div style={{width: '100%', textAlign: 'right'}}> <div style={{width: '100%', textAlign: 'right'}}>
<button <button
className="btn btn-square btn-inverse-light btn-xs d-inline-block mt-2 mb-0" className="btn btn-square btn-inverse-light btn-xs d-inline-block mt-2 mb-0"
onClick={handleUpload} disabled={!selectedFile || uploadFileMutation.isPending || uploadFileMutation.isSuccess}> onClick={handleUpload}
disabled={!selectedFile || uploadFileMutation.isPending || uploadFileMutation.isSuccess}>
Upload Upload
</button> </button>
</div> </div>
@@ -180,15 +181,18 @@ console.log('imageLink', imageLink)
<p className='text-danger'>{error?.message}</p> <p className='text-danger'>{error?.message}</p>
</div> </div>
: :
<div className="card-body scrollbar scroll_dark" style={{minHeight: '400px', maxHeight: '500px', overflowY: 'auto'}}> <div className="card-body scrollbar scroll_dark"
style={{minHeight: '400px', maxHeight: '500px', overflowY: 'auto'}}>
{mediaFileList && mediaFileList?.file_list && mediaFileList?.file_list.map((item, index) => { {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 file_url = (mediaFileList?.media_server + "/" + item?.file_group + "/" + item?.file_uid + "/" + item.filename).toLowerCase();
const avtarImage = const avtarImage =
item?.file_type === undefined item?.file_type === undefined
? "icons/01.png" ? "icons/01.png"
: "icons/" + item.file_type + ".png"; : "icons/" + item.file_type + ".png";
return (<div key={index} className={`widget-text ${imageLink == file_url && 'bg-light'}`}> return (<div key={index}
<div className={`media align-items-center`} onClick={()=>setImageLink(file_url)} style={{cursor: 'pointer'}}> 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)} <img src={getImage(avtarImage)}
// src={`assets/img/file-icon/${item.file_type}.png`} // src={`assets/img/file-icon/${item.file_type}.png`}
className="img-fluid" className="img-fluid"
@@ -202,7 +206,8 @@ console.log('imageLink', imageLink)
className="btn btn-icon btn-round btn-outline-success"> className="btn btn-icon btn-round btn-outline-success">
<i className="ti ti-download"></i> <i className="ti ti-download"></i>
</a> </a>
<a href="" className="btn btn-icon btn-round btn-outline-danger ml-2"> <a href=""
className="btn btn-icon btn-round btn-outline-danger ml-2">
<i className="ti ti-close"></i> <i className="ti ti-close"></i>
</a> </a>
</div> </div>
@@ -221,9 +226,10 @@ console.log('imageLink', imageLink)
<h4 className="card-title">Preview</h4> <h4 className="card-title">Preview</h4>
</div> </div>
</div> </div>
<div className="card-body d-flex justify-content-center align-items-center pl-0 pr-0 scrollbar scroll_dark"> <div
className="card-body d-flex justify-content-center align-items-center pl-0 pr-0 scrollbar scroll_dark">
{imageLink && {imageLink &&
<img className="w-100 h-auto" src={imageLink} alt='file-image' /> <img className="w-100 h-auto" src={imageLink} alt='file-image'/>
} }
</div> </div>
<div className="card-header d-flex justify-content-between align-items-center"> <div className="card-header d-flex justify-content-between align-items-center">
@@ -1,65 +1,66 @@
import React, {memo, useState} from 'react' import React, { useState } from "react";
import getImage from "../../../utils/getImage"; //import getImage from "../../../utils/getImage";
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'; import { useQuery, useQueryClient } from "@tanstack/react-query";
import queryKeys from '../../../services/queryKeys'; import queryKeys from "../../../services/queryKeys";
import {getTemplateConfig} from '../../../services/services'; import { getTemplateConfig } from "../../../services/services";
import {Link} from "react-router-dom"; //import {Link} from "react-router-dom";
import siteLinks from "../../../links/siteLinks"; //import siteLinks from "../../../links/siteLinks";
import UploadModal from './UploadModal'; import UploadModal from "./UploadModal";
const TemplateConfigure = ({productData}) => { const TemplateConfigure = ({ productData }) => {
const [selectedSectionDetails, setSelectedSectionDetails] = useState({});
// /panel/myproduct/template-config const {
data: templateData,
const queryClient = useQueryClient() isFetching,
isError,
const {data: templateData, isFetching, isError, error} = useQuery({ error,
} = useQuery({
queryKey: queryKeys.myTemplateConfig, queryKey: queryKeys.myTemplateConfig,
queryFn: () => { queryFn: () => {
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
product_id: productData?.product_id product_id: productData?.product_id,
} };
return getTemplateConfig(reqData) return getTemplateConfig(reqData);
}, },
staleTime: 0 staleTime: 0,
}) });
const templateResponse = templateData?.data const templateResponse = templateData?.data;
const templateImages = templateResponse?.template_images?.data; const templateImages = Array.isArray(templateResponse?.template_images?.data)
// debugger; ? templateResponse.template_images.data
: [];
console.log("templateResponse", templateResponse); console.log("templateResponse", templateResponse);
// const currentColorUID = templateResponse?.current_colorstyle_uid
// const color_styles = templateResponse?.color_styles
// const custom_template_name = templateResponse?.custom_template_name
return <> return (
<>
<div className="card card-statistics"> <div className="card card-statistics">
{isFetching ? {isFetching ? (
<> <>
<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>
</div> </div>
</> </>
: isError ? ) : isError ? (
<div className="row"> <div className="row">
<div className="col-12"> <div className="col-12">
<p className='text-danger'>{error?.message}</p> <p className="text-danger">{error?.message}</p>
</div> </div>
</div> </div>
: ) : (
<> <>
<div className="card-header"> <div className="card-header">
<div className="card-heading"> <div className="card-heading">
<h4 className="card-title" <h4 className="card-title" style={{ textTransform: "none" }}>
style={{textTransform: 'none'}}>{templateResponse?.template_name}</h4> {templateResponse?.template_name}
</h4>
</div> </div>
</div> </div>
<div> <div>
<div className="col-12"> <div className="col-12">
<div> <div>
@@ -70,59 +71,96 @@ const TemplateConfigure = ({productData}) => {
</div> </div>
<div> <div>
<ul className="list-unstyled"> <ul className="list-unstyled">
{templateImages && templateImages.map( {templateImages &&
(item) => { templateImages.map((item) => {
const currImage = item?.default_val; const currImage = item?.default_val;
return ( return (
<li className="media"> <li className="media">
<div style={{ <div
display: 'flex', style={{
flexDirection: 'row', display: "flex",
padding: '5px', flexDirection: "row",
backgroundColor: 'aliceblue', padding: "5px",
margin: '2px', backgroundColor: "aliceblue",
maxHeight: '150px' margin: "2px",
}}> maxHeight: "150px",
<div className='d-flex justify-content-center align-items-center' style={{padding: '6px', width: '120px', height: '100px'}}> width: "100%",
<img className="mb-xxs-0 img-fluid" }}
style={{height: 'auto', maxHeight: '100px'}} >
src={currImage} alt="image"/> <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>
<div className="media-body" style={{padding: '2px'}}> <div
<div style={{ className="media-body"
display: 'flex', style={{ padding: "2px" }}
flexDirection: 'column' >
}}> <div
<div style={{textAlign: 'right',width: '100%'}}></div> style={{
display: "flex",
flexDirection: "column",
}}
>
<div
style={{
textAlign: "right",
width: "100%",
}}
></div>
{/* [Change Image] */} {/* [Change Image] */}
<label className='w-100 text-end' data-bs-toggle="modal" data-bs-target="#verticalCenter" style={{cursor: 'pointer'}}>[Change Image]</label> <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}/> */} {/* <input id={item?.id} name={item?.id} className="d-none form-control form-control-sm" type="file" onChange={handleFileChange}/> */}
<div> <div>
<h5 className="mt-0 mb-1">{item?.name}</h5> <h5 className="mt-0 mb-1">
{item?.name}
</h5>
{item?.description} {item?.description}
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</li> </li>
) );
} })}
)
}
</ul> </ul>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</> </>
)}{" "}
</div>
} </div> <UploadModal
<UploadModal /> productId={productData?.product_id}
selectedSectionDetails={selectedSectionDetails}
/>
</> </>
} );
};
export default TemplateConfigure export default TemplateConfigure;
@@ -1,72 +1,80 @@
import {Form, Formik} from "formik"; import { Form, Formik } from "formik";
import * as Yup from "yup"; import * as Yup from "yup";
import {useMutation} from '@tanstack/react-query'; import { useMutation } from "@tanstack/react-query";
import {setExternalURL} from '../../../services/services'; import { setExternalURL } from "../../../services/services";
import { useState } from "react"; import { useState } from "react";
import { Link } from "react-router-dom";
const validationSchema = Yup.object().shape({ const validationSchema = Yup.object().shape({
url: Yup.string().required("URL is required").matches(/^https?:\/\/[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-]+\.[a-zA-Z]+/, 'Must be like: https://example.mysite.com'), url: Yup.string()
}) .required("URL is required")
.matches(
/^https?:\/\/[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-]+\.[a-zA-Z]+/,
"Must be like: https://example.mysite.com",
),
});
// const initialValues = { // const initialValues = {
// url: '', // url: '',
// }; // };
const URLConfiguration = ({productData}) => { const URLConfiguration = ({ productData }) => {
const [externalURLChanged, setExternalURLChanged] = useState(true);
const [externalURLChanged, setExternalURLChanged] = useState(true)
const initialValues = { const initialValues = {
url: productData?.external_url || '', url: productData?.external_url || "",
}; };
let defaultUrl = 'https://' + productData?.internal_url let defaultUrl = "https://" + productData?.internal_url;
let externalUrl = productData?.external_url let externalUrl = productData?.external_url;
const handleExternalURLChanged = (e) => { const handleExternalURLChanged = (e) => {
if(e.target.value == externalUrl){ if (e.target.value == externalUrl) {
setExternalURLChanged(true) setExternalURLChanged(true);
}else{ } else {
setExternalURLChanged(false) setExternalURLChanged(false);
}
} }
};
// API to set url // API to set url
const setURL = useMutation({ const setURL = useMutation({
mutationFn: (fields) => { mutationFn: (fields) => {
return setExternalURL(fields) return setExternalURL(fields);
}, },
onSuccess: (res) => { onSuccess: (res) => {
if (res.data.resultCode != '0') { if (res.data.resultCode != "0") {
// throw({message: res?.data?.resultDescription}) // throw({message: res?.data?.resultDescription})
throw({message: 'Something went wrong!'}) throw { message: "Something went wrong!" };
} }
}, },
onSettled: () => { onSettled: () => {
setTimeout(() => { setTimeout(() => {
setURL.reset() setURL.reset();
}, 3000) }, 3000);
} },
// onError: (err) => { // onError: (err) => {
// console.log('err', err) // console.log('err', err)
// } // }
}) });
const handleSubmit = (values) => { const handleSubmit = (values) => {
let reqData = { let reqData = {
token: localStorage.getItem('token'), // USER TOKEN token: localStorage.getItem("token"), // USER TOKEN
uid: localStorage.getItem('uid'), // USER UID uid: localStorage.getItem("uid"), // USER UID
subscription_uid: productData?.subscription_uid, subscription_uid: productData?.subscription_uid,
external_url: values.url external_url: values.url,
} };
setURL.mutate(reqData) setURL.mutate(reqData);
} };
return <> return (
<>
<div className="card card-statistics"> <div className="card card-statistics">
<div className="card-header"> <div className="card-header">
<div className="card-heading"> <div className="card-heading">
<h4 className="card-title" style={{textTransform: 'none'}}>{defaultUrl}</h4> <h4 className="card-title" style={{ textTransform: "none" }}>
{defaultUrl}
</h4>
</div> </div>
</div> </div>
{/*<div className="card-body">*/} {/*<div className="card-body">*/}
@@ -85,57 +93,104 @@ const URLConfiguration = ({productData}) => {
> >
{(props) => { {(props) => {
return ( return (
<Form className='w-full'> <Form className="w-full">
<div className="card card-statistics" style={{backgroundColor: '#b6e5ef'}}> <div
className="card card-statistics"
style={{ backgroundColor: "#b6e5ef" }}
>
<div className="card-header"> <div className="card-header">
<div className="card-heading"> <div className="card-heading">
<h4 className="card-title" style={{textTransform: 'none'}}>Set your own URL</h4> <h4
className="card-title"
style={{ textTransform: "none" }}
>
Set your own URL
</h4>
</div> </div>
</div> </div>
<div className="card-body"> <div className="card-body">
<div className="form-group"> <div className="form-group">
<label htmlFor="exampleInputEmail1">Enter your full URL <span <label htmlFor="exampleInputEmail1">
className={`${(props.errors.url && props.touched.url) && 'text-danger'}`}>{props.errors.url}</span></label> Enter your full URL{" "}
<input value={props.values.url} onChange={(e)=>{props.handleChange(e); handleExternalURLChanged(e)}} type="text" <span
className="form-control" id="url" aria-describedby="url" className={`${props.errors.url && props.touched.url && "text-danger"}`}
placeholder="https://example.mysite.com"/> >
{props.errors.url}
</span>
</label>
<input
value={props.values.url}
onChange={(e) => {
props.handleChange(e);
handleExternalURLChanged(e);
}}
type="text"
className="form-control"
id="url"
aria-describedby="url"
placeholder="https://example.mysite.com"
/>
</div> </div>
<div style={{width: '100%', textAlign: 'right'}}> <div style={{ width: "100%", textAlign: "right" }}>
<button <button
type="submit" type="submit"
disabled={setURL.isPending || externalURLChanged} disabled={setURL.isPending || externalURLChanged}
className="btn btn-primary" className="btn btn-primary"
> >
{setURL.isPending ? 'Loading...' : 'Submit'} {setURL.isPending ? "Loading..." : "Submit"}
</button> </button>
</div> </div>
</div> </div>
{setURL.error && {setURL.error && (
<div className="col-12"> <div className="col-12">
<p className='text-danger'>{setURL.error.message}</p> <p className="text-danger">{setURL.error.message}</p>
</div> </div>
} )}
{setURL.isSuccess && {setURL.isSuccess && (
<div className="col-12"> <div className="col-12">
<p className='text-success'>{'Completed successfully'}</p> <p className="text-success">{"Completed successfully"}</p>
</div> </div>
} )}
<div style={{backgroundColor: '#94b8c0', borderRadius: '10px', padding: '10px'}}> <div
Final steps to configure your URL:<br/> style={{
DNS:<br/> backgroundColor: "#148399",
DNS:<br/> borderRadius: "10px",
DNS:<br/> padding: "10px",
color: "white",
fontWeight: "bolder",
fontSize: "14px",
}}
>
To link your domain to your website, update your DNS record to
point to our hosting provider.
<br />
<hr />
Enter the following DNS servers in your domain settings
<br />
{process.env.REACT_APP_DNS1}
<br />
{process.env.REACT_APP_DNS2}
<hr />
<Link
target="_blank"
to={process.env.REACT_APP_DNS_LINK}
style={{ color: "#f6f5f6" }}
>
Click here for detailed instructions.
</Link>
<hr />
After updating your DNS settings, click Start Verification.
You will receive a status notification within 24 hours.
</div> </div>
</div> </div>
</Form> </Form>
); );
}} }}
</Formik> </Formik>
</> </>
} );
};
export default URLConfiguration export default URLConfiguration;
@@ -2,21 +2,24 @@ import React, { useRef, useState } from 'react'
import { Modal } from "bootstrap"; import { Modal } from "bootstrap";
import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query'; import {useMutation, useQuery, useQueryClient} from '@tanstack/react-query';
import queryKeys from '../../../services/queryKeys'; import queryKeys from '../../../services/queryKeys';
import {getMediaFileList, getTemplateConfig, uploadFile} from '../../../services/services'; import {getMediaFileList, templateMediaSet} from '../../../services/services';
export default function UploadModal() { export default function UploadModal({productId, selectedSectionDetails}) {
const [selectedFiles, setSelectedFiles] = useState([]) const queryClient = useQueryClient()
const handleSelectedFiles = (file_uid) => { const [selectedFile, setSelectedFile] = useState('')
if(selectedFiles.length && selectedFiles.includes(file_uid)){
let indexOfItem = selectedFiles.indexOf(file_uid) const handleSelectedFile = (file_uid) => {
let oldFiles = [...selectedFiles] // if(selectedFile.length && selectedFile.includes(file_uid)){
oldFiles.splice(indexOfItem, 1) // let indexOfItem = selectedFile.indexOf(file_uid)
setSelectedFiles(oldFiles) // let oldFiles = [...selectedFile]
}else{ // oldFiles.splice(indexOfItem, 1)
setSelectedFiles(prev => [...prev, file_uid]) // setSelectedFile(oldFiles)
} // }else{
// setSelectedFile(prev => [...prev, file_uid])
// }
setSelectedFile(file_uid)
} }
const modalRef = useRef(null) const modalRef = useRef(null)
@@ -37,33 +40,29 @@ export default function UploadModal() {
modal && modal.hide(); modal && modal.hide();
}; };
const uploadFileMutation = useMutation({ const changeTemplateMediaSet = useMutation({
mutationFn: (fields) => { mutationFn: (fields) => {
if(!fields.file){ if(!fields.file_uid){
throw({message: 'Please select a file first!'}) throw({message: 'Please select a file first!'})
} }
// return uploadFile(fields) return templateMediaSet(fields)
// remember to close the modal
dismissModal()
setTimeout(()=>{
uploadFileMutation.reset()
}, 3000)
}, },
onSuccess: (res) => { onSuccess: (res) => {
// console.log('res', res.data) // console.log('res', res.data)
// if(res.data.resultCode != '0' || !res?.data?.pending_uid){ if(res.data.resultCode != '0'){
// throw({message: res?.data?.resultDescription}) throw({message: res?.data?.resultDescription})
// } }
// setSelectedFile({id: '', img: ''}) setSelectedFile('')
// queryClient.refetchQueries({ dismissModal() // to close modal
// queryKey: [...queryKeys.my_files], queryClient.refetchQueries({
queryKey: [...queryKeys.myTemplateConfig],
// type: 'active', // type: 'active',
// exact: true, // exact: true,
// }) })
}, },
onSettled: () => { onSettled: () => {
setTimeout(()=>{ setTimeout(()=>{
uploadFileMutation.reset() changeTemplateMediaSet.reset()
}, 3000) }, 3000)
} }
}) })
@@ -71,10 +70,13 @@ export default function UploadModal() {
const handleUpload = () => { const handleUpload = () => {
let reqData = { let reqData = {
token: localStorage.getItem("token"), // USER TOKEN token: localStorage.getItem("token"), // USER TOKEN
member_uid: localStorage.getItem("uid"), // USER UID uid: localStorage.getItem("uid"), // USER UID
// file: selectedFile?.img product_id: productId,
file_uid: selectedFile,
image_id: selectedSectionDetails?.id
}; };
uploadFileMutation.mutate(reqData) // console.log('reqData', reqData)
changeTemplateMediaSet.mutate(reqData)
} }
const {data, isFetching, isError, error} = useQuery({ const {data, isFetching, isError, error} = useQuery({
@@ -121,9 +123,9 @@ export default function UploadModal() {
{mediaFileList?.file_list?.map(item => { {mediaFileList?.file_list?.map(item => {
const file_url = (mediaFileList?.media_server + "/" + item?.file_group + "/" + item?.file_uid + "/" + item.filename).toLowerCase(); const file_url = (mediaFileList?.media_server + "/" + item?.file_group + "/" + item?.file_uid + "/" + item.filename).toLowerCase();
return( return(
<div onClick={()=>handleSelectedFiles(item?.file_uid)} className={`p-3 text-center col-4`} style={{cursor: 'pointer'}}> <div onClick={()=>handleSelectedFile(item?.file_uid)} className={`p-3 text-center col-4`} style={{cursor: 'pointer'}}>
<div className={`p-3 ${selectedFiles.includes(item?.file_uid) && 'bg-light'}`}> <div className={`p-3 ${(selectedFile == item?.file_uid) && 'bg-light'}`} style={{Height: '250px'}}>
<img key={item?.file_uid} className="img-fluid" src={file_url} alt='file-image' /> <img key={item?.file_uid} className="img-fluid" style={{}} src={file_url} alt='file-image' />
</div> </div>
</div> </div>
) )
@@ -135,33 +137,26 @@ export default function UploadModal() {
} }
</div> </div>
} }
{/* <div style={{fontSize: '18px'}} className="" dangerouslySetInnerHTML={{__html: saleText}}/> */} {changeTemplateMediaSet.error &&
{/* {mutation.error &&
<> <>
<div className="col-12"> <div className="col-12">
<p className='text-danger'>{mutation.error.message}</p> <p className='text-danger'>{changeTemplateMediaSet.error.message}</p>
</div> </div>
</> </>
} }
{mutation.isSuccess && {changeTemplateMediaSet.isSuccess &&
<> <>
<div className="col-12"> <div className="col-12">
<p className='text-success'>{'subscription is successful'}</p> <p className='text-success'>{'subscription is successful'}</p>
</div> </div>
</> </>
} */} }
{/* {requestStatus.message && (
<div className="col-12">
<p className={`p-2 text-center ${requestStatus.status ? 'text-success' : 'text-danger'}`}>{requestStatus.message}</p>
</div>
)} */}
</div> </div>
<div className="modal-footer"> <div className="modal-footer">
<button type="button" className="btn btn-danger" data-bs-dismiss="modal">Cancel</button> <button type="button" className="btn btn-danger" data-bs-dismiss="modal">Cancel</button>
{selectedFiles.length > 0 && {selectedFile &&
<button type="button" className="btn btn-primary" disabled={uploadFileMutation?.isPending || uploadFileMutation?.isSuccess} onClick={handleUpload}>{uploadFileMutation?.isPending ? 'Upload...' : uploadFileMutation?.isSuccess ? 'Uploaded' : 'Upload'}</button> <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>
+23 -136
View File
@@ -1,6 +1,6 @@
import React, { useState } from "react"; import React, {useState} from "react";
import { useQuery } from "@tanstack/react-query"; import {useQuery} from "@tanstack/react-query";
import { getPaymentReports } from "../../services/services"; import {getPaymentReports} from "../../services/services";
import queryKeys from "../../services/queryKeys"; import queryKeys from "../../services/queryKeys";
export default function PaymentReportTable() { export default function PaymentReportTable() {
@@ -16,10 +16,13 @@ export default function PaymentReportTable() {
page page
} }
return getPaymentReports(reqData) return getPaymentReports(reqData)
} },
staleTime: 0
}) })
console.log('DATA', data?.data) // console.log('DATA', data?.data)
const paymentReportData = data?.data?.payment || []
return ( return (
<> <>
<div className="row"> <div className="row">
@@ -50,144 +53,28 @@ export default function PaymentReportTable() {
<table id="export-table" className="table table-bordered"> <table id="export-table" className="table table-bordered">
<thead className="thead-light"> <thead className="thead-light">
<tr> <tr>
<th>Added</th>
<th>Name</th> <th>Name</th>
<th>Position</th> <th>Amount</th>
<th>Office</th> <th>Status</th>
<th>Age</th>
<th>Start date</th>
<th>Salary</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> {paymentReportData.length > 0 ? paymentReportData.map((item, index) => {
<td>Tiger Nixon</td> return (
<td>System Architect</td> <tr key={index}>
<td>Edinburgh</td> <td>{item?.added}</td>
<td>61</td> <td>{item?.option_name}</td>
<td>2011/04/25</td> <td>{item?.currency}{item?.amount}</td>
<td>$320,800</td> <td>{item?.status}</td>
</tr> </tr>
)
})
:
<tr> <tr>
<td>Garrett Winters</td> <td colSpan={4} className='text-center'>No data found</td>
<td>Accountant</td>
<td>Tokyo</td>
<td>63</td>
<td>2011/07/25</td>
<td>$170,750</td>
</tr> </tr>
<tr> }
<td>Ashton Cox</td>
<td>Junior Technical Author</td>
<td>San Francisco</td>
<td>66</td>
<td>2009/01/12</td>
<td>$86,000</td>
</tr>
<tr>
<td>Cedric Kelly</td>
<td>Senior Javascript Developer</td>
<td>Edinburgh</td>
<td>22</td>
<td>2012/03/29</td>
<td>$433,060</td>
</tr>
<tr>
<td>Airi Satou</td>
<td>Accountant</td>
<td>Tokyo</td>
<td>33</td>
<td>2008/11/28</td>
<td>$162,700</td>
</tr>
<tr>
<td>Brielle Williamson</td>
<td>Integration Specialist</td>
<td>New York</td>
<td>61</td>
<td>2012/12/02</td>
<td>$372,000</td>
</tr>
<tr>
<td>Herrod Chandler</td>
<td>Sales Assistant</td>
<td>San Francisco</td>
<td>59</td>
<td>2012/08/06</td>
<td>$137,500</td>
</tr>
<tr>
<td>Rhona Davidson</td>
<td>Integration Specialist</td>
<td>Tokyo</td>
<td>55</td>
<td>2010/10/14</td>
<td>$327,900</td>
</tr>
<tr>
<td>Colleen Hurst</td>
<td>Javascript Developer</td>
<td>San Francisco</td>
<td>39</td>
<td>2009/09/15</td>
<td>$205,500</td>
</tr>
<tr>
<td>Sonya Frost</td>
<td>Software Engineer</td>
<td>Edinburgh</td>
<td>23</td>
<td>2008/12/13</td>
<td>$103,600</td>
</tr>
<tr>
<td>Jena Gaines</td>
<td>Office Manager</td>
<td>London</td>
<td>30</td>
<td>2008/12/19</td>
<td>$90,560</td>
</tr>
<tr>
<td>Quinn Flynn</td>
<td>Support Lead</td>
<td>Edinburgh</td>
<td>22</td>
<td>2013/03/03</td>
<td>$342,000</td>
</tr>
<tr>
<td>Charde Marshall</td>
<td>Regional Director</td>
<td>San Francisco</td>
<td>36</td>
<td>2008/10/16</td>
<td>$470,600</td>
</tr>
<tr>
<td>Haley Kennedy</td>
<td>Senior Marketing Designer</td>
<td>London</td>
<td>43</td>
<td>2012/12/18</td>
<td>$313,500</td>
</tr>
<tr>
<td>Tatyana Fitzpatrick</td>
<td>Regional Director</td>
<td>London</td>
<td>19</td>
<td>2010/03/17</td>
<td>$385,750</td>
</tr>
<tr>
<td>Michael Silva</td>
<td>Marketing Designer</td>
<td>London</td>
<td>66</td>
<td>2012/11/27</td>
<td>$198,500</td>
</tr>
</tbody> </tbody>
</table> </table>
+22 -137
View File
@@ -1,6 +1,6 @@
import React, { useState } from "react"; import React, {useState} from "react";
import { useQuery } from "@tanstack/react-query"; import {useQuery} from "@tanstack/react-query";
import { getProductReports } from "../../services/services"; import {getProductReports} from "../../services/services";
import queryKeys from "../../services/queryKeys"; import queryKeys from "../../services/queryKeys";
export default function ProductReportTable() { export default function ProductReportTable() {
@@ -16,10 +16,12 @@ export default function ProductReportTable() {
page page
} }
return getProductReports(reqData) return getProductReports(reqData)
} },
staleTime: 0
}) })
console.log('DATA', data?.data) // console.log('DATA', data?.data)
const productReportData = data?.data?.product || []
return ( return (
<> <>
@@ -53,146 +55,29 @@ export default function ProductReportTable() {
<table id="export-table" className="table table-bordered"> <table id="export-table" className="table table-bordered">
<thead className="thead-light"> <thead className="thead-light">
<tr> <tr>
<th>ID</th>
<th>Added</th>
<th>Name</th> <th>Name</th>
<th>Position</th> <th>Status</th>
<th>Office</th>
<th>Age</th>
<th>Start date</th>
<th>Salary</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> {productReportData.length > 0 ? productReportData.map((item, index) => {
<td>Tiger Nixon</td> return (
<td>System Architect</td> <tr key={index}>
<td>Edinburgh</td> <td>{item?.product_id}</td>
<td>61</td> <td>{item?.added}</td>
<td>2011/04/25</td> <td>{item?.product_name}</td>
<td>$320,800</td> <td>{item?.status}</td>
</tr> </tr>
)
})
:
<tr> <tr>
<td>Garrett Winters</td> <td colSpan={4} className='text-center'>No data found</td>
<td>Accountant</td>
<td>Tokyo</td>
<td>63</td>
<td>2011/07/25</td>
<td>$170,750</td>
</tr> </tr>
<tr> }
<td>Ashton Cox</td>
<td>Junior Technical Author</td>
<td>San Francisco</td>
<td>66</td>
<td>2009/01/12</td>
<td>$86,000</td>
</tr>
<tr>
<td>Cedric Kelly</td>
<td>Senior Javascript Developer</td>
<td>Edinburgh</td>
<td>22</td>
<td>2012/03/29</td>
<td>$433,060</td>
</tr>
<tr>
<td>Airi Satou</td>
<td>Accountant</td>
<td>Tokyo</td>
<td>33</td>
<td>2008/11/28</td>
<td>$162,700</td>
</tr>
<tr>
<td>Brielle Williamson</td>
<td>Integration Specialist</td>
<td>New York</td>
<td>61</td>
<td>2012/12/02</td>
<td>$372,000</td>
</tr>
<tr>
<td>Herrod Chandler</td>
<td>Sales Assistant</td>
<td>San Francisco</td>
<td>59</td>
<td>2012/08/06</td>
<td>$137,500</td>
</tr>
<tr>
<td>Rhona Davidson</td>
<td>Integration Specialist</td>
<td>Tokyo</td>
<td>55</td>
<td>2010/10/14</td>
<td>$327,900</td>
</tr>
<tr>
<td>Colleen Hurst</td>
<td>Javascript Developer</td>
<td>San Francisco</td>
<td>39</td>
<td>2009/09/15</td>
<td>$205,500</td>
</tr>
<tr>
<td>Sonya Frost</td>
<td>Software Engineer</td>
<td>Edinburgh</td>
<td>23</td>
<td>2008/12/13</td>
<td>$103,600</td>
</tr>
<tr>
<td>Jena Gaines</td>
<td>Office Manager</td>
<td>London</td>
<td>30</td>
<td>2008/12/19</td>
<td>$90,560</td>
</tr>
<tr>
<td>Quinn Flynn</td>
<td>Support Lead</td>
<td>Edinburgh</td>
<td>22</td>
<td>2013/03/03</td>
<td>$342,000</td>
</tr>
<tr>
<td>Charde Marshall</td>
<td>Regional Director</td>
<td>San Francisco</td>
<td>36</td>
<td>2008/10/16</td>
<td>$470,600</td>
</tr>
<tr>
<td>Haley Kennedy</td>
<td>Senior Marketing Designer</td>
<td>London</td>
<td>43</td>
<td>2012/12/18</td>
<td>$313,500</td>
</tr>
<tr>
<td>Tatyana Fitzpatrick</td>
<td>Regional Director</td>
<td>London</td>
<td>19</td>
<td>2010/03/17</td>
<td>$385,750</td>
</tr>
<tr>
<td>Michael Silva</td>
<td>Marketing Designer</td>
<td>London</td>
<td>66</td>
<td>2012/11/27</td>
<td>$198,500</td>
</tr>
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
+12 -5
View File
@@ -1,4 +1,4 @@
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 {useQuery} from "@tanstack/react-query";
import queryKeys from "../../services/queryKeys"; import queryKeys from "../../services/queryKeys";
@@ -11,6 +11,8 @@ import SystemReportTable from "./SystemReportTable";
export default function Reports() { export default function Reports() {
const [activeTab, setActiveTab] = useState('payment')
const {data, isFetching, isError, error} = useQuery({ const {data, isFetching, isError, error} = useQuery({
queryKey: queryKeys.topics, queryKey: queryKeys.topics,
queryFn: () => { queryFn: () => {
@@ -49,7 +51,7 @@ export default function Reports() {
: :
<div> <div>
<div> <div>
<div className="card card-statistics" style={{minHeight: '550px'}}> <div className="card card-statistics" style={{minHeight: '500px'}}>
{/*<div className="card-header">*/} {/*<div className="card-header">*/}
{/* <div className="card-heading">*/} {/* <div className="card-heading">*/}
{/* <h4 className="card-title"> Tab vertical </h4>*/} {/* <h4 className="card-title"> Tab vertical </h4>*/}
@@ -62,7 +64,7 @@ export default function Reports() {
<ul className="nav nav-tabs" id="myTab" role="tablist"> <ul className="nav nav-tabs" id="myTab" role="tablist">
{sortedReportTopicList && sortedReportTopicList.map((item, index) => { {sortedReportTopicList && sortedReportTopicList.map((item, index) => {
return ( return (
<li key={index} className="nav-item" role="presentation"> <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"> <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} {item?.name}
</a> </a>
@@ -72,14 +74,19 @@ export default function Reports() {
</ul> </ul>
{/* <!-- Tab Content --> */} {/* <!-- Tab Content --> */}
<div className="tab-content"> {/* <div className="tab-content">
{sortedReportTopicList && sortedReportTopicList.map((item, index) => { {sortedReportTopicList && sortedReportTopicList.map((item, index) => {
return ( return (
<div key={index} className={`tab-pane fade show ${index == 0 && 'active'}`} id={`content-${item?.url}`} role="tabpanel"> <div key={index} className={`tab-pane fade show ${index == 0 && 'active'}`} id={`content-${item?.url}`} role="tabpanel" style={{minHeight: '400px'}}>
{renderedTable[item?.url]} {renderedTable[item?.url]}
</div> </div>
) )
})} })}
</div> */}
<div className="tab-content">
<div className={`tab-pane fade show active`} style={{minHeight: '400px'}}>
{renderedTable[activeTab]}
</div>
</div> </div>
</div> </div>
</div> </div>
+22 -137
View File
@@ -1,6 +1,6 @@
import React, { useState } from "react"; import React, {useState} from "react";
import { useQuery } from "@tanstack/react-query"; import {useQuery} from "@tanstack/react-query";
import { getSystemReports } from "../../services/services"; import {getSystemReports} from "../../services/services";
import queryKeys from "../../services/queryKeys"; import queryKeys from "../../services/queryKeys";
export default function SystemReportTable() { export default function SystemReportTable() {
@@ -17,9 +17,11 @@ export default function SystemReportTable() {
} }
return getSystemReports(reqData) return getSystemReports(reqData)
}, },
staleTime: 0
}) })
console.log('DATA', data?.data) // console.log('DATA', data?.data)
const systemReportData = data?.data?.system || []
return ( return (
<> <>
@@ -53,146 +55,29 @@ export default function SystemReportTable() {
<table id="export-table" className="table table-bordered"> <table id="export-table" className="table table-bordered">
<thead className="thead-light"> <thead className="thead-light">
<tr> <tr>
<th>Name</th> <th>Added</th>
<th>Position</th> <th>Action Name</th>
<th>Office</th> <th>Description</th>
<th>Age</th> <th>Updated</th>
<th>Start date</th>
<th>Salary</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> {systemReportData.length > 0 ? systemReportData.map((item, index) => {
<td>Tiger Nixon</td> return (
<td>System Architect</td> <tr key={index}>
<td>Edinburgh</td> <td>{item?.added}</td>
<td>61</td> <td>{item?.action_name}</td>
<td>2011/04/25</td> <td>{item?.status_description}</td>
<td>$320,800</td> <td>{item?.updated}</td>
</tr> </tr>
)
})
:
<tr> <tr>
<td>Garrett Winters</td> <td colSpan={4} className='text-center'>No data found</td>
<td>Accountant</td>
<td>Tokyo</td>
<td>63</td>
<td>2011/07/25</td>
<td>$170,750</td>
</tr> </tr>
<tr> }
<td>Ashton Cox</td>
<td>Junior Technical Author</td>
<td>San Francisco</td>
<td>66</td>
<td>2009/01/12</td>
<td>$86,000</td>
</tr>
<tr>
<td>Cedric Kelly</td>
<td>Senior Javascript Developer</td>
<td>Edinburgh</td>
<td>22</td>
<td>2012/03/29</td>
<td>$433,060</td>
</tr>
<tr>
<td>Airi Satou</td>
<td>Accountant</td>
<td>Tokyo</td>
<td>33</td>
<td>2008/11/28</td>
<td>$162,700</td>
</tr>
<tr>
<td>Brielle Williamson</td>
<td>Integration Specialist</td>
<td>New York</td>
<td>61</td>
<td>2012/12/02</td>
<td>$372,000</td>
</tr>
<tr>
<td>Herrod Chandler</td>
<td>Sales Assistant</td>
<td>San Francisco</td>
<td>59</td>
<td>2012/08/06</td>
<td>$137,500</td>
</tr>
<tr>
<td>Rhona Davidson</td>
<td>Integration Specialist</td>
<td>Tokyo</td>
<td>55</td>
<td>2010/10/14</td>
<td>$327,900</td>
</tr>
<tr>
<td>Colleen Hurst</td>
<td>Javascript Developer</td>
<td>San Francisco</td>
<td>39</td>
<td>2009/09/15</td>
<td>$205,500</td>
</tr>
<tr>
<td>Sonya Frost</td>
<td>Software Engineer</td>
<td>Edinburgh</td>
<td>23</td>
<td>2008/12/13</td>
<td>$103,600</td>
</tr>
<tr>
<td>Jena Gaines</td>
<td>Office Manager</td>
<td>London</td>
<td>30</td>
<td>2008/12/19</td>
<td>$90,560</td>
</tr>
<tr>
<td>Quinn Flynn</td>
<td>Support Lead</td>
<td>Edinburgh</td>
<td>22</td>
<td>2013/03/03</td>
<td>$342,000</td>
</tr>
<tr>
<td>Charde Marshall</td>
<td>Regional Director</td>
<td>San Francisco</td>
<td>36</td>
<td>2008/10/16</td>
<td>$470,600</td>
</tr>
<tr>
<td>Haley Kennedy</td>
<td>Senior Marketing Designer</td>
<td>London</td>
<td>43</td>
<td>2012/12/18</td>
<td>$313,500</td>
</tr>
<tr>
<td>Tatyana Fitzpatrick</td>
<td>Regional Director</td>
<td>London</td>
<td>19</td>
<td>2010/03/17</td>
<td>$385,750</td>
</tr>
<tr>
<td>Michael Silva</td>
<td>Marketing Designer</td>
<td>London</td>
<td>66</td>
<td>2012/11/27</td>
<td>$198,500</td>
</tr>
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
+16 -16
View File
@@ -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'}`}>
+1
View File
@@ -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();
+18 -11
View File
@@ -1,17 +1,21 @@
import React, { memo, useRef, useState } from 'react' import React, { memo, useRef, useState } from 'react'
// import { useSelector } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import getImage from '../../utils/getImage'; import getImage from '../../utils/getImage';
import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useMutation, useQueryClient } from '@tanstack/react-query';
import { uploadProfileImg } from '../../services/services'; import { uploadProfileImg } from '../../services/services';
import queryKeys from '../../services/queryKeys'; import queryKeys from '../../services/queryKeys';
import { updateUserDetails } from '../../store/UserDetails'
const ProfileImage = memo(({intialData}) => { const ProfileImage = memo(({intialData}) => {
const dispatch = useDispatch()
const queryClient = useQueryClient() const queryClient = useQueryClient()
const [selectedImg, setSelectedImg] = useState(null) const [selectedImg, setSelectedImg] = useState(null)
// const {userDetails} = useSelector((state) => state?.userDetails); // CHECKS FOR ACTIVE USER DETAILS // const {userDetails} = useSelector((state) => state?.userDetails); // CHECKS FOR ACTIVE USER DETAILS
const avtarImage = "avtar/merms-user.png"; const avtarImage = "avtar/merms-user.png";
// browser profile img // browser profile img
@@ -26,23 +30,26 @@ const ProfileImage = memo(({intialData}) => {
const uploadProfileMutation = useMutation({ const uploadProfileMutation = useMutation({
mutationFn: (fields) => { mutationFn: (fields) => {
if(!fields.img){ if(!fields.file){
throw new Error('Please, select an image') throw new Error('Please, select an image')
} }
return uploadProfileImg(fields) return uploadProfileImg(fields)
}, },
onSuccess: (res) => { onSuccess: (res) => {
if(res.data.resultCode != '0'){ console.log('res', res)
throw({message: res?.data?.resultDescription ? res?.data?.resultDescription : 'An error occured'}) 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 // const account_name = res?.data?.personal_data?.account_name
// dispatch(updateUserDetails({ account_name }));
}, },
onSettled: ()=>{ onSettled: ()=>{
setTimeout(() => { setTimeout(() => {
queryClient.refetchQueries({ // queryClient.refetchQueries({
queryKey: [...queryKeys.profile_data], // type: 'active', // exact: true, // queryKey: [...queryKeys.profile_data], // type: 'active', // exact: true,
}) // })
uploadProfileMutation.reset() uploadProfileMutation.reset()
}, 3000); }, 3000);
} }
@@ -51,8 +58,8 @@ const ProfileImage = memo(({intialData}) => {
const proceedToUpload = () => { const proceedToUpload = () => {
let reqData = { let reqData = {
token: localStorage.getItem('token'), // USER TOKEN token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid'), // USER UID member_uid: localStorage.getItem('uid'), // USER UID
img: selectedImg file: selectedImg
} }
// console.log('reqData', reqData) // console.log('reqData', reqData)
uploadProfileMutation.mutate(reqData) uploadProfileMutation.mutate(reqData)
@@ -95,7 +102,7 @@ const ProfileImage = memo(({intialData}) => {
{selectedImg && {selectedImg &&
<div> <div>
<button onClick={proceedToUpload} disabled={uploadProfileMutation.isSuccess || uploadProfileMutation.isPending} className="btn btn-light text-primary mb-2"> <button onClick={proceedToUpload} disabled={uploadProfileMutation.isSuccess || uploadProfileMutation.isPending} className="btn btn-light text-primary mb-2">
{uploadProfileMutation.isPaused ? 'Upload...' : 'Upload New Avatar'} {uploadProfileMutation.isPending ? 'Upload...' : 'Upload New Avatar'}
</button> </button>
</div> </div>
} }
+1 -1
View File
@@ -1,6 +1,6 @@
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";
@@ -1,14 +1,29 @@
import React from 'react'; import React from "react";
import { loadStripe } from '@stripe/stripe-js'; import { loadStripe } from "@stripe/stripe-js";
import { Elements, useStripe, useElements, CardElement } from '@stripe/react-stripe-js'; import {
import {MyProductData, StripeSubscriptionCreate} from '../../services/services'; Elements,
import {useQuery} from "@tanstack/react-query"; useStripe,
useElements,
CardElement,
} from "@stripe/react-stripe-js";
import {
MyProductData,
StripeSubscriptionCreate,
} from "../../services/services";
import { useQuery } from "@tanstack/react-query";
import queryKeys from "../../services/queryKeys"; import queryKeys from "../../services/queryKeys";
import { useNavigate } from 'react-router-dom'; import { useNavigate } from "react-router-dom";
//const stripePromise = loadStripe('your_stripe_publishable_key'); //const stripePromise = loadStripe('your_stripe_publishable_key');
const stripePromise = loadStripe('pk_test_51RqL5WLjZLojw6IZmEpwFidNZSl9lLlVUHNvuFZNEz1eTR9XXepnyyVhfvXe9cp4eMnqkDPpoe9wxLLRSV0dxRee00UfhayUOT'); const stripePromise = loadStripe(
"pk_test_51RqL5WLjZLojw6IZmEpwFidNZSl9lLlVUHNvuFZNEz1eTR9XXepnyyVhfvXe9cp4eMnqkDPpoe9wxLLRSV0dxRee00UfhayUOT",
);
const CheckoutForm = ({ priceId, customerId ,option_name }) => { const CheckoutForm = ({
priceId,
customerId,
option_name,
selected_display_name,
}) => {
const stripe = useStripe(); const stripe = useStripe();
const elements = useElements(); const elements = useElements();
const navigate = useNavigate(); const navigate = useNavigate();
@@ -20,36 +35,49 @@ const CheckoutForm = ({ priceId, customerId ,option_name }) => {
} }
let reqData = { let reqData = {
priceId : priceId, priceId: priceId,
customerId: customerId, customerId: customerId,
option_name: option_name, option_name: option_name,
token: localStorage.getItem('token'), // USER TOKEN token: localStorage.getItem("token"), // USER TOKEN
uid: localStorage.getItem('uid') // USER UID uid: localStorage.getItem("uid"), // USER UID
} };
StripeSubscriptionCreate(reqData).then( (res)=>{ StripeSubscriptionCreate(reqData).then((res) => {
console.log(res); console.log(res);
console.log(res.data.stripe_session); console.log(res.data.stripe_session);
//navigate(res.data.stripe_session) //navigate(res.data.stripe_session)
window.location.replace(res.data.stripe_session); window.location.replace(res.data.stripe_session);
}); });
}; };
return ( return (
<form onSubmit={handleSubmit}> <form onSubmit={handleSubmit}>
<CardElement /> {/*<CardElement />*/}
<button type="submit" disabled={!stripe}> <button
Subscribe type="submit"
disabled={!stripe}
className="btn btn-primary text-uppercase"
>
Start {selected_display_name} Subscription
</button> </button>
</form> </form>
); );
}; };
const StripeSubscriptionButton = ({ priceId, customerId ,option_name}) => { const StripeSubscriptionButton = ({
priceId,
customerId,
option_name,
selected_display_name,
}) => {
return ( return (
<Elements stripe={stripePromise}> <Elements stripe={stripePromise}>
<CheckoutForm priceId={priceId} customerId={customerId} option_name={option_name} /> <CheckoutForm
priceId={priceId}
customerId={customerId}
option_name={option_name}
selected_display_name={selected_display_name}
/>
</Elements> </Elements>
); );
}; };
+19 -15
View File
@@ -5,15 +5,14 @@ import SubscribeNewCard from "./SubscribeNewCard";
import SubscribePreviousCard from "./SubscribePreviousCard"; import SubscribePreviousCard from "./SubscribePreviousCard";
import SubcribePaymentOptions from "./SubcribePaymentOptions"; import SubcribePaymentOptions from "./SubcribePaymentOptions";
import StripeSubscriptionButton from "./StripeSubscriptionButton"; import StripeSubscriptionButton from "./StripeSubscriptionButton";
import SubscribeInfo from "./SubscribeInfo";
export default function Subscribe() { export default function Subscribe() {
const {state: {selectedSubscription,customerId}} = useLocation() const {state: {selectedSubscription, customerId, currentSubscription}} = useLocation()
console.log('selectedSubscription', selectedSubscription) console.log('selectedSubscription', selectedSubscription)
console.log('selectedSubscription.option_name',selectedSubscription.option_name) console.log('currentSubscription', currentSubscription)
console.log('selectedSubscription.option_name', selectedSubscription.option_name)
console.log('customerId', customerId) console.log('customerId', customerId)
let [activePaymentType, setActivePaymentType] = useState('previous') let [activePaymentType, setActivePaymentType] = useState('previous')
@@ -27,17 +26,22 @@ export default function Subscribe() {
<div className="card card-statistics text-center py-3"> <div className="card card-statistics text-center py-3">
<div className="card-body pricing-content"> <div className="card-body pricing-content">
<div className="pricing-content-card"> <div className="pricing-content-card">
<h5>Current Subscription(s)</h5> <h3>Your Current Subscription</h3>
{/*<h2 className="text-primary pt-3">{currentSubscription?.display_name}</h2>*/} <h2 className="text-primary pt-3">{currentSubscription?.display_name}</h2>
<SubcribePaymentOptions activePaymentType={activePaymentType} {/*<SubcribePaymentOptions activePaymentType={activePaymentType}*/}
setActivePaymentType={setActivePaymentType}/> {/* setActivePaymentType={setActivePaymentType}/>*/}
{activePaymentType == 'new' ? {/*{activePaymentType == 'new' ?*/}
<SubscribeNewCard/> {/* <SubscribeNewCard/>*/}
: {/* :*/}
<SubscribePreviousCard/> {/* <SubscribePreviousCard/>*/}
} {/*}*/}
<> <>
<StripeSubscriptionButton priceId={selectedSubscription.stripe_price_id} customerId={customerId} option_name={selectedSubscription.option_name} /> <SubscribeInfo />
<StripeSubscriptionButton priceId={selectedSubscription.stripe_price_id}
customerId={customerId}
option_name={selectedSubscription.option_name}
selected_display_name={selectedSubscription.display_name}
/>
</> </>
</div> </div>
</div> </div>
+25
View File
@@ -0,0 +1,25 @@
import React from 'react'
export default function SubscribeInfo() {
return <>
<div className="row">
<div className="col-md-12 col-12 selects-contant">
<div className="card card-statistics">
<div className="card-body">
<div className="form-group mb-0">
Your subscription terms outline the details of your plan, including billing frequency,
renewal dates, payment methods, and cancellation policies. Please review your subscription
agreement for information on your current plan, how to manage or update your subscription,
and any applicable fees or renewal conditions. Contact support if you have questions about
your subscription.
</div>
</div>
</div>
</div>
</div>
</>
}
+2 -1
View File
@@ -91,7 +91,8 @@ export default function Subscription() {
navigate(siteLinks.subscribe, { navigate(siteLinks.subscribe, {
state: { state: {
selectedSubscription: value, selectedSubscription: value,
customerId: stripe_customer_id customerId: stripe_customer_id,
currentSubscription: currentSubscription
} }
}) })
}} }}
+1 -1
View File
@@ -2072,7 +2072,7 @@ ul.activity {
} }
.img-icon i{ .img-icon i{
font-size:20px; font-size:35px;
} }
@media (max-width: 1440px) and (min-width:1200px){ @media (max-width: 1440px) and (min-width:1200px){
.border-xxl-t{ .border-xxl-t{
-1
View File
@@ -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'
+13 -5
View File
@@ -34,8 +34,8 @@ const postAuxEnd = (path, postData, media=false) => {
return axios.post(`${basePath}${path}`, newPostData).then(res => { 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);
}) })
} }
@@ -105,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
@@ -298,6 +298,14 @@ export const uploadFile = (reqData) => {
return postAuxEnd(`/upload/webfiles`, postData, true) 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) => { export const getReportsTopicsList = (reqData) => {
let postData = { let postData = {
...reqData, ...reqData,
@@ -350,8 +358,8 @@ export const uploadProfileImg = (reqData) => {
let postData = { let postData = {
...reqData, ...reqData,
} }
throw new Error('Opps') return postAuxEnd(`/upload/profile-picture`, postData, true)
// return postAuxEnd(`/panel/account/profile-update`, postData, true) // throw new Error('Opps')
} }
+1 -1
View File
@@ -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 };
}, },
}, },
}); });