Compare commits

...

13 Commits

Author SHA1 Message Date
victorAnumudu 7ad1a585ea added refresh message display 2025-10-06 17:13:28 +01:00
CHIEFSOFT\ameye a8c2dd84f1 provison room 2025-10-06 11:52:38 -04:00
CHIEFSOFT\ameye ddcc6f0cd2 Rebuild site text change 2025-10-05 14:00:30 -04:00
CHIEFSOFT\ameye 683f81e8a6 customn temaplte 2025-10-05 13:53:11 -04:00
CHIEFSOFT\ameye 8e09c30c5c fix error on display 2025-10-05 13:18:16 -04:00
ameye af0d4db5de Merge branch 'external-url-populate' of MERMS/MermsPanelReactJS into master 2025-10-04 10:02:39 +00:00
victorAnumudu 6f3dae4116 populated externl URL 2025-10-04 10:23:29 +01:00
CHIEFSOFT\ameye 13900793af added external URL 2025-10-03 20:34:31 -04:00
CHIEFSOFT\ameye 698c89edfc fix URL page 2025-10-03 15:46:03 -04:00
CHIEFSOFT\ameye 4f5a383c99 Url configuration 2025-10-03 15:16:16 -04:00
ameye a5b6a11880 Merge branch 'set-url-endpoint' of MERMS/MermsPanelReactJS into master 2025-10-03 18:30:58 +00:00
victorAnumudu 0f58da3dce added set external url endpoint 2025-10-03 17:36:10 +01:00
ameye 1101e80d91 Merge branch 'set-url' of MERMS/MermsPanelReactJS into master 2025-09-30 20:17:32 +00:00
8 changed files with 216 additions and 110 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

+1 -1
View File
@@ -41,7 +41,7 @@ export default function SocketIOContextProvider({children}) {
socket.on(socketOnEvents.receive_message, (data) => { socket.on(socketOnEvents.receive_message, (data) => {
// 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('DATA', data) console.log('SOCKET RECEIVED DATA *** ', data)
queryClient.refetchQueries({ queryClient.refetchQueries({
queryKey: [...queryKeys.recentAction], queryKey: [...queryKeys.recentAction],
// type: 'active', // type: 'active',
+1 -1
View File
@@ -59,7 +59,7 @@ export default function DashPayments() {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{payments.length > 0 ? {payments && payments?.length > 0 ?
payments.map((item, index) => { payments.map((item, index) => {
return ( return (
<tr key={index}> <tr key={index}>
+20 -3
View File
@@ -1,21 +1,26 @@
import React, { useMemo, useRef, useState } from "react"; import React, {useEffect, useMemo, useRef, useState} from "react";
import { useSelector } from "react-redux"; import { useSelector } from "react-redux";
import getImage from "../../utils/getImage"; import getImage from "../../utils/getImage";
import { useMutation, useQuery } from "@tanstack/react-query"; import { useMutation, useQuery } from "@tanstack/react-query";
import { productRefreshSite, getSettingsData } from "../../services/services"; import { productRefreshSite, getSettingsData } from "../../services/services";
import Settings from "./settingsTab/Settings"; import Settings from "./settingsTab/Settings";
import queryKeys from "../../services/queryKeys"; import queryKeys from "../../services/queryKeys";
import {SocketContextValues} from "../context/SocketIOContext";
export default function ProductActive({productData}){ export default function ProductActive({productData}){
const {joinRoom} = SocketContextValues() // Destructures values from socket context
const iframe = useRef() const iframe = useRef()
const [refreshMsg, setRefreshMsg] = useState('')
const refresh = useMutation({ const refresh = useMutation({
mutationFn: (fields) => { mutationFn: (fields) => {
return productRefreshSite(fields) return productRefreshSite(fields)
}, },
onSuccess: (res) => { onSuccess: (res) => {
setRefreshMsg(res?.data?.message)
setTimeout(()=>{setRefreshMsg('')},3000)
iframe.current.src += '' iframe.current.src += ''
} }
}) })
@@ -31,6 +36,13 @@ export default function ProductActive({productData}){
} }
let externalUrl= 'https://'+productData?.internal_url let externalUrl= 'https://'+productData?.internal_url
const productSubUID = productData.subscription_uid;
useEffect(() => {
const provision_room = "PROVISION_"+productSubUID;
console.log("JOINING ROOM ON ACTIVE *** ", provision_room);
joinRoom(provision_room); // provision subscription room
}, [])
return( return(
<> <>
{/*<BreadcrumbComBS title='Active Product Name' paths={['Dashboard', 'Product']} />*/} {/*<BreadcrumbComBS title='Active Product Name' paths={['Dashboard', 'Product']} />*/}
@@ -58,11 +70,16 @@ export default function ProductActive({productData}){
<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">
<button type="button" onClick={handleRefresh} className="btn btn-primary">{refresh.isPending ? 'Loading...' : 'Refresh Site'} <div className="d-flex justify-end gap-3">
{refreshMsg &&
<p className="text-success text-center">{refreshMsg}</p>
}
<button type="button" onClick={handleRefresh} className="btn btn-primary">{refresh.isPending ? 'Initiating...' : 'Rebuild Site'}
</button> </button>
</div> </div>
</div> </div>
</div> </div>
</div>
<div className="col-xxl-6"> <div className="col-xxl-6">
<div className="card card-statistics"> <div className="card card-statistics">
<div className="card-header"> <div className="card-header">
+12 -5
View File
@@ -28,7 +28,9 @@ export default function ProductProvision(props){
const provisionData = provision?.data const provisionData = provision?.data
useEffect(() => { useEffect(() => {
joinRoom(productSubUID); // provision subscription room const provision_room = "PROVISION_"+productSubUID;
console.log("JOINING ROOM ON START *** ", provision_room);
joinRoom(provision_room); // provision subscription room
}, []) }, [])
return ( return (
@@ -59,8 +61,11 @@ export default function ProductProvision(props){
</div> </div>
<div className="card-body"> <div className="card-body">
<div className="progress"> <div className="progress">
<div className="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" <div className="progress-bar progress-bar-striped progress-bar-animated"
aria-valuenow={`${provisionData?.percent_completed}%`} aria-valuemin="0" aria-valuemax="100" style={{width:`${provisionData?.percent_completed}%`}} ></div> role="progressbar"
aria-valuenow={`${provisionData?.percent_completed}%`}
aria-valuemin="0" aria-valuemax="100"
style={{width: `${provisionData?.percent_completed}%`}}></div>
</div> </div>
</div> </div>
</div> </div>
@@ -108,8 +113,10 @@ export default function ProductProvision(props){
<div className="col-lg-6"> <div className="col-lg-6">
<div className="card card-statistics "> <div className="card card-statistics ">
<h4 className="card-title" style={{padding:'10px'}}>Started creating your selection</h4> <h4 className="card-title" style={{padding: '10px'}}>Started creating your
<img className="card-img-top" src={getImage('widget/working.jpg')} alt="Card image cap" /> selection</h4>
<img className="card-img-top" src={getImage('widget/working.jpg')}
alt="Card image cap"/>
{/* <div className="card-body"> {/* <div className="card-body">
<div className="" dangerouslySetInnerHTML={{__html: productDescription}}/> <div className="" dangerouslySetInnerHTML={{__html: productDescription}}/>
</div> */} </div> */}
@@ -3,6 +3,8 @@ import getImage from "../../../utils/getImage";
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 {getProductTemplateData, activateTemplate} from '../../../services/services'; import {getProductTemplateData, activateTemplate} from '../../../services/services';
import {Link} from "react-router-dom";
import siteLinks from "../../../links/siteLinks";
const SiteTemplateSelector = memo(({name = 'Full Name', data, productData}) => { const SiteTemplateSelector = memo(({name = 'Full Name', data, productData}) => {
@@ -60,7 +62,23 @@ const SiteTemplateSelector = memo(({name = 'Full Name', data, productData}) => {
} }
if (custom_template_name && custom_template_name != '') { if (custom_template_name && custom_template_name != '') {
// This implies we have a custom template , just return here // This implies we have a custom template , just return here
return <>This product is using a custom template named {custom_template_name} </> return <>
<div className='col-12'>
<div
className="rounded-2 d-flex flex-column justify-content-between align-items-center"
style={{backgroundColor: '#F2FAF7'}}>
<h4 className='p-4 text-black'
style={{marginBottom: '20px'}}>Custom Product Template.</h4>
<img className='' style={{width: '200px'}}
src={getImage('custom-template.png')}
alt='mail-alert'/>
<h4 className='p-4 text-black'
style={{marginTop: '20px'}}>This product is using a custom template named <span
style={{color: 'darkred'}}>&ldquo;{custom_template_name}&rdquo;</span> .</h4>
</div>
</div>
</>
} }
return ( return (
<div className="page-account-form"> <div className="page-account-form">
@@ -1,27 +1,52 @@
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 { completePWDReset } from '../../../services/services'; import {setExternalURL} from '../../../services/services';
import { useState } from "react";
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 initialValues = {
url: productData?.external_url || '',
};
let defaultUrl = 'https://' + productData?.internal_url let defaultUrl = 'https://' + productData?.internal_url
let externalUrl = productData?.external_url
const handleExternalURLChanged = (e) => {
if(e.target.value == externalUrl){
setExternalURLChanged(true)
}else{
setExternalURLChanged(false)
}
}
// API to set url // API to set url
const setURL = useMutation({ const setURL = useMutation({
mutationFn: (fields) => { mutationFn: (fields) => {
return completePWDReset(fields) return setExternalURL(fields)
}, },
// onSuccess: (res) => { onSuccess: (res) => {
// }, if (res.data.resultCode != '0') {
// throw({message: res?.data?.resultDescription})
throw({message: 'Something went wrong!'})
}
},
onSettled: () => {
setTimeout(() => {
setURL.reset()
}, 3000)
}
// onError: (err) => { // onError: (err) => {
// console.log('err', err) // console.log('err', err)
// } // }
@@ -29,27 +54,28 @@ const URLConfiguration = ({productData}) => {
const handleSubmit = (values) => { const handleSubmit = (values) => {
let reqData = { let reqData = {
url: values.url token: localStorage.getItem('token'), // USER TOKEN
uid: localStorage.getItem('uid'), // USER UID
subscription_uid: productData?.subscription_uid,
external_url: values.url
} }
console.log('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">Default URL</h4> <h4 className="card-title" style={{textTransform: 'none'}}>{defaultUrl}</h4>
</div> </div>
</div> </div>
<div className="card-body"> {/*<div className="card-body">*/}
<div className="form-group"> {/* <div className="form-group">*/}
{/*<label htmlFor="exampleInputEmail1">Email address</label>*/} {/* /!*<label htmlFor="exampleInputEmail1">Email address</label>*!/*/}
<input type="email" className="form-control" {/* <input type="email" className="form-control"*/}
aria-describedby="defaultUrlHelp" value={defaultUrl} readOnly={true} /> {/* aria-describedby="defaultUrlHelp" value={defaultUrl} readOnly={true} />*/}
</div> {/* </div>*/}
{/*<button type="submit" className="btn btn-primary">Submit</button>*/} {/*</div>*/}
</div>
</div> </div>
<Formik <Formik
@@ -60,7 +86,7 @@ const URLConfiguration = ({productData}) => {
{(props) => { {(props) => {
return ( return (
<Form className='w-full'> <Form className='w-full'>
<div className="card card-statistics" style={{backgroundColor:'#7affd92b'}}> <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>
@@ -68,10 +94,40 @@ const URLConfiguration = ({productData}) => {
</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 className={`${(props.errors.url && props.touched.url) && 'text-danger'}`}>{props.errors.url}</span></label> <label htmlFor="exampleInputEmail1">Enter your full URL <span
<input value={props.values.url} onChange={props.handleChange} type="text" className="form-control" id="url" aria-describedby="url" placeholder="https://example.mysite.com"/> 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"
className="form-control" id="url" aria-describedby="url"
placeholder="https://example.mysite.com"/>
</div> </div>
<button type="submit" className="btn btn-primary">Submit</button> <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 &&
<div className="col-12">
<p className='text-danger'>{setURL.error.message}</p>
</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>
</div> </div>
</Form> </Form>
+8
View File
@@ -246,6 +246,14 @@ export const getCommonPractice = (reqData) => {
return postAuxEnd(`/panel/common/practice`, postData, false) return postAuxEnd(`/panel/common/practice`, postData, false)
} }
// FUNCTION TO SET EXTERNAL URL
export const setExternalURL = (reqData) => {
let postData = {
...reqData
}
return postAuxEnd('/panel/myproduct/external-url', postData, false)
}