Decorate all existing pages

This commit is contained in:
Yang Li 2025-05-11 14:35:31 -04:00
parent 334bd5542b
commit e70fb22ac3
15 changed files with 675 additions and 269 deletions

View File

@ -1,16 +1,16 @@
{
"files": {
"main.css": "/static/css/main.2fa2d232.css",
"main.js": "/static/js/main.77186374.js",
"main.js": "/static/js/main.da419ea1.js",
"static/js/787.c4e7f8f9.chunk.js": "/static/js/787.c4e7f8f9.chunk.js",
"static/media/landing.png": "/static/media/landing.d4c6072db7a67dff6a78.png",
"index.html": "/index.html",
"main.2fa2d232.css.map": "/static/css/main.2fa2d232.css.map",
"main.77186374.js.map": "/static/js/main.77186374.js.map",
"main.da419ea1.js.map": "/static/js/main.da419ea1.js.map",
"787.c4e7f8f9.chunk.js.map": "/static/js/787.c4e7f8f9.chunk.js.map"
},
"entrypoints": [
"static/css/main.2fa2d232.css",
"static/js/main.77186374.js"
"static/js/main.da419ea1.js"
]
}

View File

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script><link rel="manifest" href="/manifest.json"/><title>Worldshine Transportation</title><script defer="defer" src="/static/js/main.77186374.js"></script><link href="/static/css/main.2fa2d232.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script><link rel="manifest" href="/manifest.json"/><title>Worldshine Transportation</title><script defer="defer" src="/static/js/main.da419ea1.js"></script><link href="/static/css/main.2fa2d232.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

View File

@ -96,9 +96,11 @@ const CustomerReport = () => {
const dateText = ((date.getMonth() > 8) ? (date.getMonth() + 1) : ('0' + (date.getMonth() + 1))) + '/' + ((date.getDate() > 9) ? date.getDate() : ('0' + date.getDate())) + '/' + date.getFullYear();
TransRoutesService.getAll(dateText).then(data => {
setRoutes(data.data);
setShowDateDropdown(false)
})
ReportService.getReportsByDateAndType(dateText, REPORT_TYPE.ADMIN_CUSTOMER_REPORT).then(data => {
setExistedReports(data.data);
setShowDateDropdown(false);
})
}
@ -748,7 +750,7 @@ const CustomerReport = () => {
className="me-2"
show={showDateDropdown}
onToggle={() => setShowDateDropdown(!showDateDropdown)}
autoClose="outside"
autoClose={false}
>
<Dropdown.Toggle variant="primary">
<CalendarWeek size={16} className="me-2"></CalendarWeek>Select Date to View Report
@ -761,7 +763,7 @@ const CustomerReport = () => {
className="me-2"
show={showFilterReportDropdown}
onToggle={() => setShowFilterReportDropdown(!showFilterReportDropdown)}
autoClose="outside"
autoClose={false}
>
<Dropdown.Toggle variant="primary">
<Filter size={16} className="me-2"></Filter>Filter

View File

@ -2,6 +2,8 @@ import React, {useState, useEffect} from "react";
import { useDispatch } from "react-redux";
import { useNavigate } from "react-router-dom";
import { AuthService, CenterPhoneService } from "../../services";
import { Spinner, Breadcrumb, BreadcrumbItem, Tabs, Tab } from "react-bootstrap";
import { Columns, Download, Send, PencilSquare, PersonSquare, Plus } from "react-bootstrap-icons";
const CenterPhoneList = () => {
const navigate = useNavigate();
@ -30,45 +32,71 @@ const CenterPhoneList = () => {
}
const redirectTo = () => {
navigate(`/messages/list`)
}
const goToEdit = (id) => {
navigate(`/center-phones/edit/${id}`)
}
const goToCreateNew = () => {
navigate(`/center-phones`)
}
return (
<>
<div className="list row mb-4">
<Breadcrumb>
<Breadcrumb.Item>General</Breadcrumb.Item>
<Breadcrumb.Item active>
Center Phone
</Breadcrumb.Item>
</Breadcrumb>
<div className="col-md-12 text-primary">
<h5>All Phones <button className="btn btn-link btn-sm" onClick={() => {redirectToAdmin()}}>Back</button></h5>
<h4>
All Phones <button className="btn btn-link btn-sm" onClick={() => {redirectTo()}}>Back</button>
</h4>
</div>
</div>
<div className="list row mb-4">
<div className="col-md-12">
<div className="mb-4">Keyword: <input type="text" value={keyword} onChange={(e) => setKeyword(e.currentTarget.value)}/></div>
<table className="personnel-info-table">
<thead>
<tr>
<th>Phone Title</th>
<th>Phone Number</th>
<th>Activated</th>
<th></th>
</tr>
</thead>
<tbody>
{
phones && phones.filter((item)=> item?.phone_number.includes(keyword) || item?.phone_title.toLowerCase().includes(keyword.toLowerCase())).map(phone => <tr key={phone.id}>
<td>{phone?.phone_title}</td>
<td>{phone?.phone_number}</td>
<td>{phone?.activated ? 'Yes': 'No'}</td>
<td>
<button className="btn btn-primary btn-sm me-2" onClick={() => goToEdit(phone?.id)}>Edit</button>
</td>
</tr>)
}
</tbody>
</table>
<div className="app-main-content-list-container">
<div className="app-main-content-list-func-container">
<Tabs defaultActiveKey="allMessages" id="messages-tab">
<Tab eventKey="allMessages" title="All Messages">
<table className="personnel-info-table">
<thead>
<tr>
<th className="th-index">No.</th>
<th>Phone Title</th>
<th>Phone Number</th>
<th>Activated</th>
</tr>
</thead>
<tbody>
{
phones && phones.filter((item)=> item?.phone_number.includes(keyword) || item?.phone_title.toLowerCase().includes(keyword.toLowerCase())).map((phone, index )=> <tr key={phone.id}>
<td className="td-index">{index + 1}</td>
<td> <PencilSquare size={16} className="clickable me-2" onClick={() => goToEdit(phone?.id)}></PencilSquare> { phone?.phone_title }</td>
<td>{phone?.phone_number}</td>
<td>{phone?.activated ? 'Yes': 'No'}</td>
<td>
<button className="btn btn-primary btn-sm" onClick={() => goToEdit(phone?.id)}>Edit</button>
</td>
</tr>)
}
</tbody>
</table>
</Tab>
</Tabs>
<div className="list-func-panel">
<input className="me-2 with-search-icon" type="text" placeholder="Search" value={keyword} onChange={(e) => setKeyword(e.currentTarget.value)} />
{/* <button className="btn btn-primary me-2"><Columns size={16} className="me-2"></Columns>Manage Table</button> */}
<button className="btn btn-primary me-2" onClick={() => goToCreateNew()}><Plus size={16}></Plus>Add New Phone</button>
{/* <button className="btn btn-primary"><Download size={16} className="me-2"></Download>Export</button> */}
</div>
</div>
</div>
</>

View File

@ -1,6 +1,7 @@
import React, {useEffect, useState} from "react";
import { useNavigate } from "react-router-dom";
import { AuthService, CenterPhoneService } from "../../services";
import { Spinner, Breadcrumb, BreadcrumbItem, Tabs, Tab } from "react-bootstrap";
const CreateCenterPhone = () => {
const navigate = useNavigate();
@ -18,11 +19,12 @@ const CreateCenterPhone = () => {
const redirectTo = () => {
if (params.get('from') === 'medical') {
navigate(`/medical/`);
} else {
navigate(`/admin/customer-report`)
}
// if (params.get('from') === 'medical') {
// navigate(`/medical/`);
// } else {
// navigate(`/admin/customer-report`)
//}
navigate(`/center-phones/list`);
}
@ -32,7 +34,7 @@ const CreateCenterPhone = () => {
phone_number: phoneNumber
};
CenterPhoneService.createNewCenterPhone(data).then(() => {
navigate(`/center-phones/list`)
navigate(`/center-phones/list`);
});
}
@ -40,22 +42,44 @@ const CreateCenterPhone = () => {
return (
<>
<div className="list row mb-4">
<Breadcrumb>
<Breadcrumb.Item>General</Breadcrumb.Item>
<Breadcrumb.Item active>
Center Phone
</Breadcrumb.Item>
</Breadcrumb>
<div className="col-md-12 text-primary">
<h5>Create New Center Phone Item <button className="btn btn-link btn-sm" onClick={() => {redirectTo()}}>Back</button></h5>
<h4>
Create Center Phone <button className="btn btn-link btn-sm" onClick={() => {redirectTo()}}>Back</button>
</h4>
</div>
</div>
<div className="list row mb-4">
<div className="col-md-4 mb-4">
<div>Phone Title(*):</div> <input type="text" value={phoneTitle || ''} onChange={e => setPhoneTitle(e.target.value)}/>
</div>
<div className="col-md-4 mb-4">
<div>Phone Number(*):</div> <input type="text" value={phoneNumber || ''} onChange={e => setPhoneNumber(e.target.value)}/>
</div>
</div>
<div className="list row mb-5">
<div className="col-md-6 col-sm-6 col-xs-12">
<button className="btn btn-primary btn-sm" onClick={() => savePhone()}> Save </button>
<button className="btn btn-default btn-sm" onClick={() => redirectTo()}> Cancel </button>
<div className="app-main-content-list-container">
<div className="app-main-content-list-func-container">
<Tabs defaultActiveKey="phoneCreation" id="phone-creation-tab">
<Tab eventKey="phoneCreation" title="Create Center Phone">
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Phone Title
<span className="required">*</span>
</div>
<input type="text" value={phoneTitle || ''} onChange={e => setPhoneTitle(e.target.value)}/>
</div>
<div className="me-4">
<div className="field-label">Phone Number
<span className="required">*</span>
</div>
<input type="text" value={phoneNumber || ''} onChange={e => setPhoneNumber(e.target.value)}/>
</div>
</div>
<div className="col-md-12 col-sm-12 col-xs-12">
<button className="btn btn-default btn-sm float-right" onClick={() => redirectTo()}> Cancel </button>
<button className="btn btn-primary btn-sm float-right" onClick={() => savePhone()}> Save </button>
</div>
</Tab>
</Tabs>
</div>
</div>
</>

View File

@ -1,6 +1,7 @@
import React, {useEffect, useState} from "react";
import { useNavigate, useParams } from "react-router-dom";
import { AuthService, CenterPhoneService } from "../../services";
import { Spinner, Breadcrumb, BreadcrumbItem, Tabs, Tab } from "react-bootstrap";
const UpdateCenterPhone = () => {
const navigate = useNavigate();
@ -46,25 +47,49 @@ const UpdateCenterPhone = () => {
return (
<>
<div className="list row mb-4">
<Breadcrumb>
<Breadcrumb.Item>General</Breadcrumb.Item>
<Breadcrumb.Item active>
Center Phone
</Breadcrumb.Item>
</Breadcrumb>
<div className="col-md-12 text-primary">
<h5>Update Phone <button className="btn btn-link btn-sm" onClick={() => {redirectTo()}}>Back</button></h5>
<h4>
Update Center Phone <button className="btn btn-link btn-sm" onClick={() => {redirectTo()}}>Back</button>
</h4>
</div>
</div>
<div className="list row mb-4">
<div className="col-md-4 mb-4">
<div>Phone Title(*):</div> <input type="text" value={phoneTitle || ''} onChange={e => setPhoneTitle(e.target.value)}/>
</div>
<div className="col-md-4 mb-4">
<div>Phone Number(*):</div> <input type="text" value={phoneNumber || ''} onChange={e => setPhoneNumber(e.target.value)}/>
</div>
<div className="col-md-4 mb-4">
<div>Activated:</div> <input type="checkbox" value={activated} checked={activated === true} onChange={e => setActivated(!activated)}/>
</div>
</div>
<div className="list row mb-5">
<div className="col-md-6 col-sm-6 col-xs-12">
<button className="btn btn-primary btn-sm me-2 mb-2" onClick={() => savePhone()}> Save </button>
<button className="btn btn-default btn-sm mb-2" onClick={() => redirectTo()}> Cancel </button>
<div className="app-main-content-list-container">
<div className="app-main-content-list-func-container">
<Tabs defaultActiveKey="updatePhone" id="update-phone-tab">
<Tab eventKey="updatePhone" title="Update Center Phone">
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Phone Title
<span className="required">*</span>
</div>
<input type="text" value={phoneTitle || ''} onChange={e => setPhoneTitle(e.target.value)}/>
</div>
<div className="me-4">
<div className="field-label">Phone Number
<span className="required">*</span>
</div>
<input type="text" value={phoneNumber || ''} onChange={e => setPhoneNumber(e.target.value)}/>
</div>
<div className="me-4">
<div className="field-label">Activated
</div>
<input type="checkbox" value={activated} checked={activated === true} onChange={e => setActivated(!activated)}/>
</div>
</div>
<div className="col-md-12 col-sm-12 col-xs-12">
<button className="btn btn-default btn-sm float-right" onClick={() => redirectTo()}> Cancel </button>
<button className="btn btn-primary btn-sm float-right" onClick={() => savePhone()}> Save </button>
</div>
</Tab>
</Tabs>
</div>
</div>
</>

View File

@ -283,7 +283,42 @@ const CreateCustomer = () => {
<input type="email" placeholder="e.g.,example@gmail.com" className="long" value={email || ''} onChange={e => setEmail(e.target.value)}/>
</div>
</div>
{/* We will do Address and Emergency later */}
<h6 className="text-primary">Home Addresses</h6>
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Address 1 <span className="required">*</span></div>
<input type="text" value={address1 || ''} onChange={e => setAddress1(e.target.value)}/>
</div>
</div>
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Address 2</div>
<input type="text" value={address2 || ''} onChange={e => setAddress2(e.target.value)}/>
</div>
<div className="me-4">
<div className="field-label">Address 3</div>
<input type="text" value={address3 || ''} onChange={e => setAddress3(e.target.value)}/>
</div>
<div className="me-4">
<div className="field-label">Address 4</div>
<input type="text" value={address4 || ''} onChange={e => setAddress4(e.target.value)}/>
</div>
<div className="me-4">
<div className="field-label">Address 5</div>
<input type="text" value={address5 || ''} onChange={e => setAddress5(e.target.value)}/>
</div>
</div>
<h6 className="text-primary">Emergency Contact Information</h6>
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Emergency Contact <span className="required">*</span> </div>
<input type="text" placeholder="e.g.,John 240-463-1698" className="long" value={emergencyContact || ''} onChange={e => setEmergencyContact(e.target.value)}/>
</div>
</div>
<h6 className="text-primary">Service Information</h6>
<div className="app-main-content-fields-section">
<div className="me-4">

View File

@ -465,6 +465,40 @@ const UpdateCustomer = () => {
</div>
</div>
{/* We will do Address and Emergency later */}
{/* We will do Address and Emergency later */}
<h6 className="text-primary">Home Addresses</h6>
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Address 1 <span className="required">*</span></div>
<input type="text" value={address1 || ''} onChange={e => setAddress1(e.target.value)}/>
</div>
</div>
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Address 2</div>
<input type="text" value={address2 || ''} onChange={e => setAddress2(e.target.value)}/>
</div>
<div className="me-4">
<div className="field-label">Address 3</div>
<input type="text" value={address3 || ''} onChange={e => setAddress3(e.target.value)}/>
</div>
<div className="me-4">
<div className="field-label">Address 4</div>
<input type="text" value={address4 || ''} onChange={e => setAddress4(e.target.value)}/>
</div>
<div className="me-4">
<div className="field-label">Address 5</div>
<input type="text" value={address5 || ''} onChange={e => setAddress5(e.target.value)}/>
</div>
</div>
<h6 className="text-primary">Emergency Contact Information</h6>
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Emergency Contact <span className="required">*</span> </div>
<input type="text" placeholder="e.g.,John 240-463-1698" className="long" value={emergencyContact || ''} onChange={e => setEmergencyContact(e.target.value)}/>
</div>
</div>
<h6 className="text-primary">Service Information</h6>
<div className="app-main-content-fields-section">
<div className="me-4">

View File

@ -1,77 +1,109 @@
import React, {useEffect, useState} from "react";
import { useNavigate } from "react-router-dom";
import { AuthService, MessageService } from "../../services";
import { Spinner, Breadcrumb, BreadcrumbItem, Tabs, Tab } from "react-bootstrap";
const CreateMessage = () => {
const navigate = useNavigate();
useEffect(() => {
if (!AuthService.canAddOrEditRoutes() && !AuthService.canViewRoutes() && !AuthService.canAccessLegacySystem()) {
window.alert('You haven\'t login yet OR this user does not have access to this page. Please change a dispatcher or admin account to login.')
AuthService.logout();
navigate(`/login`);
}
}, []);
const [messageGroup, setMessageGroup] = useState();
const [messageName, setMessageName] = useState('');
const [messageTitle, setMessageTitle] = useState('');
const [messageBody, setMessageBody] = useState('');
const [language, setLanguage] = useState('');
if (!AuthService.canAddOrEditRoutes() && !AuthService.canViewRoutes() && !AuthService.canAccessLegacySystem()) {
window.alert('You haven\'t login yet OR this user does not have access to this page. Please change a dispatcher or admin account to login.')
AuthService.logout();
navigate(`/login`);
}
}, []);
const [messageGroup, setMessageGroup] = useState();
const [messageName, setMessageName] = useState('');
const [messageTitle, setMessageTitle] = useState('');
const [messageBody, setMessageBody] = useState('');
const [language, setLanguage] = useState('');
const redirectTo = () => {
navigate(`/messages/list`);
}
const redirectTo = () => {
navigate(`/messages/list`);
}
const saveMessage = () => {
const data = {
message_group: messageGroup,
message_title: messageTitle,
message_body: messageBody,
message_name: messageName,
language: language
};
MessageService.createMessage(data).then(() => redirectTo())
const saveMessage = () => {
const data = {
message_group: messageGroup,
message_title: messageTitle,
message_body: messageBody,
message_name: messageName,
language: language
};
MessageService.createMessage(data).then(() => redirectTo())
}
return (
<>
<div className="list row mb-4">
<Breadcrumb>
<Breadcrumb.Item>General</Breadcrumb.Item>
<Breadcrumb.Item active>
Messaging
</Breadcrumb.Item>
</Breadcrumb>
<div className="col-md-12 text-primary">
<h5>Create New Message Template <button className="btn btn-link btn-sm" onClick={() => {redirectTo()}}>Back</button></h5>
<h4>
Create Message Template <button className="btn btn-link btn-sm" onClick={() => {redirectTo()}}>Back</button>
</h4>
</div>
</div>
<div className="list row mb-4">
<div className="col-md-4 mb-4">
<div>Message Group (*):</div>
<select value={messageGroup} onChange={e => setMessageGroup(e.target.value)} required>
<option value=""></option>
<option value={1}>1</option>
<option value={2}>2</option>
<option value={3}>3</option>
</select>
</div>
<div className="col-md-4 mb-4">
<div>Message Name:</div> <input type="text" value={messageName || ''} onChange={e => setMessageName(e.target.value)}/>
</div>
<div className="col-md-4 mb-4">
<div>Language:</div>
<select value={language} onChange={e => setLanguage(e.target.value)}>
<option value=""></option>
<option value="English">English</option>
<option value="Chinese">Chinese</option>
<option value="Vietnamese">Vietnamese</option>
<option value="Korean">Korean</option>
</select>
</div>
<div className="col-md-12 mb-4">
<div>Message Title:</div> <input type="text" value={messageTitle || ''} onChange={e => setMessageTitle(e.target.value)}/>
</div>
<div className="col-md-12 mb-4">
<div>Message Body:</div> <textarea value={messageBody || ''} onChange={e => setMessageBody(e.target.value)}/>
</div>
<div className="col-md-6 col-sm-6 col-xs-12">
<button className="btn btn-primary btn-sm" onClick={() => saveMessage()}> Save </button>
<button className="btn btn-default btn-sm" onClick={() => redirectTo()}> Cancel </button>
<div className="app-main-content-list-container">
<div className="app-main-content-list-func-container">
<Tabs defaultActiveKey="messageCreation" id="message-template-tab">
<Tab eventKey="messageCreation" title="Create Message Template">
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Message Group
<span className="required">*</span>
</div>
<select value={messageGroup} onChange={e => setMessageGroup(e.target.value)} required>
<option value=""></option>
<option value={1}>1</option>
<option value={2}>2</option>
<option value={3}>3</option>
</select>
</div>
<div className="me-4">
<div className="field-label">Message Name
<span className="required">*</span>
</div>
<input type="text" value={messageName || ''} onChange={e => setMessageName(e.target.value)}/>
</div>
</div>
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Language
</div>
<select value={language} onChange={e => setLanguage(e.target.value)}>
<option value=""></option>
<option value="English">English</option>
<option value="Chinese">Chinese</option>
<option value="Vietnamese">Vietnamese</option>
<option value="Korean">Korean</option>
</select>
</div>
<div className="me-4">
<div className="field-label">Message Title
</div>
<input type="text" value={messageTitle || ''} onChange={e => setMessageTitle(e.target.value)}/>
</div>
</div>
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Message Body
</div>
<textarea value={messageBody || ''} onChange={e => setMessageBody(e.target.value)}/>
</div>
</div>
<div className="col-md-12 col-sm-12 col-xs-12">
<button className="btn btn-default btn-sm float-right" onClick={() => redirectTo()}> Cancel </button>
<button className="btn btn-primary btn-sm float-right" onClick={() => saveMessage()}> Save </button>
</div>
</Tab>
</Tabs>
</div>
</div>
</>

View File

@ -1,6 +1,8 @@
import React, {useState, useEffect} from "react";
import { useNavigate } from "react-router-dom";
import { AuthService, MessageService } from "../../services";
import { Spinner, Breadcrumb, BreadcrumbItem, Tabs, Tab } from "react-bootstrap";
import { Columns, Download, Send, PencilSquare, PersonSquare, Plus } from "react-bootstrap-icons";
const MessageList = () => {
const navigate = useNavigate();
@ -30,6 +32,10 @@ const MessageList = () => {
}
const goToSendMessage = () => {
navigate(`/messages/send-message`);
}
const goToEdit = (id) => {
navigate(`/messages/edit/${id}`)
}
@ -42,42 +48,53 @@ const MessageList = () => {
return (
<>
<div className="list row mb-4">
<Breadcrumb>
<Breadcrumb.Item>General</Breadcrumb.Item>
<Breadcrumb.Item active>
Messaging
</Breadcrumb.Item>
</Breadcrumb>
<div className="col-md-12 text-primary">
<h5>All Messages <button className="btn btn-link btn-sm" onClick={() => {redirectToAdmin()}}>Back</button>
<button className="btn btn-link btn-sm" onClick={() => {goToCreate()}}>Go To Create Message Template</button>
</h5>
<h4>All Messages Templates
</h4>
</div>
</div>
<div className="list row mb-4">
<div className="col-md-12">
<table className="personnel-info-table">
<thead>
<tr>
<th>Message Group</th>
<th>Message Name</th>
<th>Language</th>
<th>Message Title</th>
<th>Message Body</th>
<th></th>
</tr>
</thead>
<tbody>
{
messages && messages.map(message => <tr key={message.id}>
<td>{message?.message_group}</td>
<td>{message?.message_name}</td>
<td>{message?.language}</td>
<td>{message?.message_title}</td>
<td>{message?.message_body}</td>
<td>
<button className="btn btn-primary btn-sm me-2" onClick={() => goToEdit(message?.id)}>Edit</button>
</td>
</tr>)
}
</tbody>
</table>
<div className="app-main-content-list-container">
<div className="app-main-content-list-func-container">
<Tabs defaultActiveKey="allMessages" id="messages-tab">
<Tab eventKey="allMessages" title="All Messages">
<table className="personnel-info-table">
<thead>
<tr>
<th className="th-index">No.</th>
<th>Message Group</th>
<th>Message Name</th>
<th>Language</th>
<th>Message Title</th>
<th>Message Body</th>
</tr>
</thead>
<tbody>
{
messages && messages.map((message, index) => <tr key={message.id}>
<td className="td-index">{index + 1}</td>
<td>{message?.message_group}</td>
<td><PencilSquare size={16} className="clickable me-2" onClick={() => goToEdit(message?.id)}></PencilSquare> {message?.message_name}</td>
<td>{message?.language}</td>
<td>{message?.message_title}</td>
<td>{message?.message_body}</td>
</tr>)
}
</tbody>
</table>
</Tab>
</Tabs>
<div className="list-func-panel">
<button className="btn btn-primary me-2" onClick={() => goToCreate()}><Plus size={16}></Plus>Create New Message</button>
<button className="btn btn-primary me-2" onClick={() => goToSendMessage()}><Send size={16} className="me-2"></Send> Send Message</button>
<button className="btn btn-primary"><Download size={16} className="me-2"></Download>Export</button>
</div>
</div>
</div>
</>

View File

@ -1,6 +1,8 @@
import React, {useEffect, useState} from "react";
import { useNavigate, useParams } from "react-router-dom";
import { AuthService, MessageService } from "../../services";
import { Spinner, Breadcrumb, BreadcrumbItem, Tabs, Tab } from "react-bootstrap";
const MessageTokenEditor = () => {
const navigate = useNavigate();
@ -32,7 +34,7 @@ const MessageTokenEditor = () => {
}, [currentMessageToken])
const redirectTo = () => {
navigate(`/admin`);
navigate(`/messages/list`);
}
const saveMessageToken = () => {
@ -55,19 +57,38 @@ const MessageTokenEditor = () => {
return (
<>
<div className="list row mb-4">
<Breadcrumb>
<Breadcrumb.Item>General</Breadcrumb.Item>
<Breadcrumb.Item active>
Messaging
</Breadcrumb.Item>
</Breadcrumb>
<div className="col-md-12 text-primary">
<h5>Update Message Token <button className="btn btn-link btn-sm" onClick={() => {redirectTo()}}>Back</button></h5>
<h4>
Update Message Token <button className="btn btn-link btn-sm" onClick={() => {redirectTo()}}>Back</button>
</h4>
</div>
</div>
<div className="list row mb-4">
<div className="col-md-12 mb-4">
<div>Message Token:</div> <input type="text" value={messageToken || ''} onChange={e => setMessageToken(e.target.value)}/>
</div>
</div>
<div className="list row mb-5">
<div className="col-md-6 col-sm-6 col-xs-12">
<button className="btn btn-primary btn-sm me-2 mb-2" onClick={() => saveMessageToken()}> Save </button>
<button className="btn btn-default btn-sm mb-2" onClick={() => redirectTo()}> Cancel </button>
<div className="app-main-content-list-container">
<div className="app-main-content-list-func-container">
<Tabs defaultActiveKey="messageCreation" id="message-template-tab">
<Tab eventKey="messageCreation" title="Update Message Template">
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Message Token
<span className="required">*</span>
</div>
<input type="text" value={messageToken || ''} onChange={e => setMessageToken(e.target.value)}/>
</div>
</div>
<div className="col-md-12 col-sm-12 col-xs-12">
<button className="btn btn-default btn-sm float-right" onClick={() => redirectTo()}> Cancel </button>
<button className="btn btn-primary btn-sm float-right" onClick={() => saveMessageToken()}> Save </button>
</div>
</Tab>
</Tabs>
</div>
</div>
</>

View File

@ -2,6 +2,8 @@ import React, {useEffect, useState} from "react";
import { useNavigate } from "react-router-dom";
import { AuthService, MessageService, CustomerService } from "../../services";
import Select from 'react-select';
import { Spinner, Breadcrumb, BreadcrumbItem, Tabs, Tab } from "react-bootstrap";
import { SendCheck } from "react-bootstrap-icons";
const SendMessage = () => {
const navigate = useNavigate();
@ -35,6 +37,14 @@ const SendMessage = () => {
}
const redirectToList = () => {
navigate(`/messages/list`)
}
const goToSentMessages = () => {
navigate(`/messages/sent-messages/list`);
}
const sendMessage = () => {
setShowSuccessInfo(false);
const data = {
@ -56,40 +66,127 @@ const SendMessage = () => {
return (
<>
<div className="list row mb-4">
<div className="col-md-12 text-primary">
<h5>Send Message <button className="btn btn-link btn-sm" onClick={() => {redirectTo()}}>Back</button></h5>
<Breadcrumb>
<Breadcrumb.Item>General</Breadcrumb.Item>
<Breadcrumb.Item active>
Messaging
</Breadcrumb.Item>
<Breadcrumb.Item active>
Send Message
</Breadcrumb.Item>
</Breadcrumb>
<div className="col-md-12 text-primary">
<h4>Send Message <button className="btn btn-link btn-sm" onClick={() => {redirectToList()}}>Back</button></h4>
</div>
</div>
<div className="list row mb-4">
<div className="col-md-12 mb-4">
<div>Type in Phone Number:</div> <input type="text" value={contactPhone || ''} onChange={e => setContactPhone(e.target.value)}/>
<div className="app-main-content-list-container">
<div className="app-main-content-list-func-container">
<Tabs defaultActiveKey="sendMessage" id="send-message-tab">
<Tab eventKey="sendMessage" title="Send Message">
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Type in Phone Number
<span className="required">*</span>
</div>
<input type="text" value={contactPhone || ''} onChange={e => setContactPhone(e.target.value)}/>
</div>
<div className="me-4">OR</div>
<div className="me-4">
<div className="field-label">Select From Participant Mobile Number List
<span className="required">*</span>
</div>
<Select styles={{
control: (baseStyles, state) => ({
...baseStyles,
width: '350px',
height: '45px',
'padding-top': 0,
'padding-bottom': 0,
'margin-top': 0,
'margin-bottom': 0
}),
indicatorSeparator: (baseStyles, state) => ({
...baseStyles,
width: 0
}),
indicatorsContainer: (baseStyles) => ({
...baseStyles,
'margin-top': '-10px'
}),
placeholder: (baseStyles) => ({
...baseStyles,
'margin-top': '-10px',
'font-size': '13px'
}),
singleValue: (baseStyles, state) => ({
...baseStyles,
'margin-top': '-10px',
'font-size': '13px'
})
}} value={contactSeniorPhone || ''} onChange={selectedData => onContactSeniorChange(selectedData)} options={[{value: '', label: ''}, ...seniorPhoneList.map(senior => ({
value: senior?.mobile_phone || '',
label: `${senior?.name}(${senior?.name_cn}) - ${senior?.mobile_phone}` || '',
}))]}></Select>
</div>
</div>
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Select Message Template (Optional)</div>
<Select styles={{
control: (baseStyles, state) => ({
...baseStyles,
width: '350px',
height: '45px',
'padding-top': 0,
'padding-bottom': 0,
'margin-top': 0,
'margin-bottom': 0
}),
indicatorSeparator: (baseStyles, state) => ({
...baseStyles,
width: 0
}),
indicatorsContainer: (baseStyles) => ({
...baseStyles,
'margin-top': '-10px'
}),
placeholder: (baseStyles) => ({
...baseStyles,
'margin-top': '-10px',
'font-size': '13px'
}),
singleValue: (baseStyles, state) => ({
...baseStyles,
'margin-top': '-10px',
'font-size': '13px'
})
}} value={messageTemplate || ''} onChange={selectedData => {setMessageTemplate(selectedData); setMessageText(selectedData.value)}} options={[{value: '', label: ''}, ...messageTempateList.map(template => ({
value: template.message_body || '',
label: template.message_body || '',
}))]}></Select>
</div>
</div>
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Message Content</div>
<textarea value={messageText || ''} onChange={e => setMessageText(e.target.value)}/>
</div>
</div>
<div className="list row mb-5">
<div className="col-md-12 col-sm-12 col-xs-12">
<button className="btn btn-default btn-sm float-right" onClick={() => redirectTo()}> Cancel </button>
<button className="btn btn-primary btn-sm float-right" onClick={() => sendMessage()}> Save </button>
</div>
</div>
{showSuccessInfo && <div className="col-md-12 mb-4 alert alert-success" role="alert">
Message Sent!
</div>}
</Tab>
</Tabs>
<div className="list-func-panel">
<button className="btn btn-primary btn-sm" onClick={() => goToSentMessages()}><SendCheck size={16} className="me-2"></SendCheck>View All Sent Messages</button>
</div>
</div>
<div className="col-md-12 mb-4">OR</div>
<div className="col-md-6 col-sm-12 col-xs-12 mb-4">
<div>Select From Participant Mobile Number List:</div>
<Select value={contactSeniorPhone || ''} onChange={selectedData => onContactSeniorChange(selectedData)} options={[{value: '', label: ''}, ...seniorPhoneList.map(senior => ({
value: senior?.mobile_phone || '',
label: `${senior?.name}(${senior?.name_cn}) - ${senior?.mobile_phone}` || '',
}))]}></Select>
</div>
<div className="col-md-12 col-sm-12 col-xs-12 mb-4">
<div>Select Message Template (Not Required):</div>
<Select value={messageTemplate || ''} onChange={selectedData => {setMessageTemplate(selectedData); setMessageText(selectedData.value)}} options={[{value: '', label: ''}, ...messageTempateList.map(template => ({
value: template.message_body || '',
label: template.message_body || '',
}))]}></Select>
</div>
<div className="col-md-12 mb-4">
<div>Message Text:</div> <textarea value={messageText || ''} onChange={e => setMessageText(e.target.value)}/>
</div>
<div className="col-md-6 col-sm-6 col-xs-12 mb-4">
<button className="btn btn-primary btn-sm" onClick={() => sendMessage()}> Send Message </button>
<button className="btn btn-default btn-sm" onClick={() => redirectTo()}> Cancel </button>
</div>
{showSuccessInfo && <div className="col-md-12 mb-4 alert alert-success" role="alert">
Message Sent!
</div>}
</div>
</>
);

View File

@ -2,11 +2,14 @@ import React, {useState, useEffect} from "react";
import { useNavigate } from "react-router-dom";
import { AuthService, MessageService } from "../../services";
import DatePicker from "react-datepicker";
import { CalendarWeek, ClockHistory, Copy, Download, Eraser, Plus, Clock, Send, Filter, CalendarCheck, Check } from "react-bootstrap-icons";
import { Breadcrumb, Tabs, Tab, Dropdown, Spinner, Modal, Button } from "react-bootstrap";
const SentMessageList = () => {
const navigate = useNavigate();
const [messages, setMessages] = useState([]);
const [datePicked, setDatePicked] = useState(new Date());
const [showDateDropdown, setShowDateDropdown] = useState(false);
const params = new URLSearchParams(window.location.search);
useEffect(() => {
if (!AuthService.canAddOrEditRoutes() && !AuthService.canViewRoutes()&&!AuthService.canAccessLegacySystem()) {
@ -20,6 +23,14 @@ const SentMessageList = () => {
})
}, []);
const cleanDate = () => {
setDatePicked(new Date());
setShowDateDropdown(false);
}
const FilterAndClose = () => {
setShowDateDropdown(false);
}
const redirectToAdmin = () => {
@ -31,45 +42,95 @@ const SentMessageList = () => {
}
const redirectToSend = () => {
navigate(`/messages/send-message`);
}
const customMenuDate = React.forwardRef(
({ children, style, className, 'aria-labelledby': labeledBy }, ref) => {
return (
<div
ref={ref}
style={style}
className={className}
aria-labelledby={labeledBy}
>
<div className="app-main-content-fields-section margin-sm dropdown-container">
<div className="me-4">
<div className="field-label">Select Date to Filter</div>
<DatePicker selected={datePicked} onChange={(v) => setDatePicked(v)} />
</div>
</div>
<div className="list row">
<div className="col-md-12">
<button className="btn btn-default btn-sm float-right" onClick={() => cleanDate()}> Cancel </button>
<button className="btn btn-primary btn-sm float-right" onClick={() => FilterAndClose()}>Filter</button>
</div>
</div>
</div>
);
},
);
return (
<>
<div className="list row mb-4">
<Breadcrumb>
<Breadcrumb.Item>General</Breadcrumb.Item>
<Breadcrumb.Item active>
Messaging
</Breadcrumb.Item>
</Breadcrumb>
<div className="col-md-12 text-primary">
<h5>All Sent Messages <button className="btn btn-link btn-sm" onClick={() => {redirectToAdmin()}}>Back</button>
</h5>
<h4>All Sent Messages <button className="btn btn-link btn-sm" onClick={() => {redirectToSend()}}>Back</button>
</h4>
</div>
</div>
<div className="list row mb-4">
<div className="mb-4">
Pick a Date to Filter:
</div>
<div className="col-md-4 col-sm-4 col-xs-12 mb-4">
<DatePicker selected={datePicked} onChange={(v) => setDatePicked(v)} />
</div>
<div className="col-md-12">
<table className="personnel-info-table">
<thead>
<tr>
<th>From</th>
<th>To</th>
<th>Message</th>
<th>Sent Time</th>
</tr>
</thead>
<tbody>
{
messages && messages.filter((message) => (new Date(message?.create_date))?.toLocaleDateString() === (new Date(datePicked)).toLocaleDateString()).map(message => <tr key={message.id}>
<td>{message?.from}</td>
<td>{message?.to}</td>
<td>{message?.content}</td>
<td>{`${new Date(message?.create_date)?.toLocaleDateString()} ${new Date(message?.create_date)?.toLocaleTimeString()}`}</td>
</tr>)
}
</tbody>
</table>
<div className="app-main-content-list-container">
<div className="app-main-content-list-func-container">
<Tabs defaultActiveKey="allSentMessages" id="sent-messages-tab">
<Tab eventKey="allSentMessages" title="All Sent Messages">
<table className="personnel-info-table">
<thead>
<tr>
<th className="th-index">No.</th>
<th>From</th>
<th>To</th>
<th>Message</th>
<th>Sent Time</th>
</tr>
</thead>
<tbody>
{
messages && messages.filter((message) => (new Date(message?.create_date))?.toLocaleDateString() === (new Date(datePicked)).toLocaleDateString()).map((message, index) => <tr key={message.id}>
<td className="td-index">{index + 1}</td>
<td>{message?.from}</td>
<td>{message?.to}</td>
<td>{message?.content}</td>
<td>{`${new Date(message?.create_date)?.toLocaleDateString()} ${new Date(message?.create_date)?.toLocaleTimeString()}`}</td>
</tr>)
}
</tbody>
</table>
</Tab>
</Tabs>
<div className="list-func-panel">
<Dropdown
key={'sent-date'}
id="sent-date"
className="me-2"
show={showDateDropdown}
onToggle={() => setShowDateDropdown(!showDateDropdown)}
autoClose={false}
>
<Dropdown.Toggle variant="primary">
<CalendarWeek size={16} className="me-2"></CalendarWeek>Select Date to Filter
</Dropdown.Toggle>
<Dropdown.Menu as={customMenuDate}/>
</Dropdown>
</div>
</div>
</div>
</>

View File

@ -1,6 +1,7 @@
import React, {useEffect, useState} from "react";
import { useNavigate, useParams } from "react-router-dom";
import { AuthService, MessageService } from "../../services";
import { Spinner, Breadcrumb, BreadcrumbItem, Tabs, Tab } from "react-bootstrap";
const UpdateMessage = () => {
const navigate = useNavigate();
@ -55,44 +56,73 @@ const UpdateMessage = () => {
return (
<>
<div className="list row mb-4">
<Breadcrumb>
<Breadcrumb.Item>General</Breadcrumb.Item>
<Breadcrumb.Item active>
Messaging
</Breadcrumb.Item>
</Breadcrumb>
<div className="col-md-12 text-primary">
<h5>Update Message <button className="btn btn-link btn-sm" onClick={() => {redirectTo()}}>Back</button></h5>
<h4>
Update Message Template <button className="btn btn-link btn-sm" onClick={() => {redirectTo()}}>Back</button>
</h4>
</div>
</div>
<div className="list row mb-4">
<div className="col-md-4 mb-4">
<div>Message Group (*):</div>
<select value={messageGroup} onChange={e => setMessageGroup(e.target.value)} required>
<option value=""></option>
<option value={1}>1</option>
<option value={2}>2</option>
<option value={3}>3</option>
</select>
</div>
<div className="col-md-4 mb-4">
<div>Message Name:</div> <input type="text" value={messageName || ''} onChange={e => setMessageName(e.target.value)}/>
</div>
<div className="col-md-4 mb-4">
<div>Language:</div>
<select value={language} onChange={e => setLanguage(e.target.value)}>
<option value=""></option>
<option value="English">English</option>
<option value="Chinese">Chinese</option>
<option value="Vietnamese">Vietnamese</option>
<option value="Korean">Korean</option>
</select>
</div>
<div className="col-md-12 mb-4">
<div>Message Title:</div> <input type="text" value={messageTitle || ''} onChange={e => setMessageTitle(e.target.value)}/>
</div>
<div className="col-md-12 mb-4">
<div>Message Body:</div> <textarea value={messageBody || ''} onChange={e => setMessageBody(e.target.value)}/>
</div>
</div>
<div className="list row mb-5">
<div className="col-md-6 col-sm-6 col-xs-12">
<button className="btn btn-primary btn-sm me-2 mb-2" onClick={() => saveMessage()}> Save </button>
<button className="btn btn-default btn-sm mb-2" onClick={() => redirectTo()}> Cancel </button>
<div className="app-main-content-list-container">
<div className="app-main-content-list-func-container">
<Tabs defaultActiveKey="messageCreation" id="message-template-tab">
<Tab eventKey="messageCreation" title="Update Message Template">
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Message Group
<span className="required">*</span>
</div>
<select value={messageGroup} onChange={e => setMessageGroup(e.target.value)} required>
<option value=""></option>
<option value={1}>1</option>
<option value={2}>2</option>
<option value={3}>3</option>
</select>
</div>
<div className="me-4">
<div className="field-label">Message Name
<span className="required">*</span>
</div>
<input type="text" value={messageName || ''} onChange={e => setMessageName(e.target.value)}/>
</div>
</div>
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Language
</div>
<select value={language} onChange={e => setLanguage(e.target.value)}>
<option value=""></option>
<option value="English">English</option>
<option value="Chinese">Chinese</option>
<option value="Vietnamese">Vietnamese</option>
<option value="Korean">Korean</option>
</select>
</div>
<div className="me-4">
<div className="field-label">Message Title
</div>
<input type="text" value={messageTitle || ''} onChange={e => setMessageTitle(e.target.value)}/>
</div>
</div>
<div className="app-main-content-fields-section">
<div className="me-4">
<div className="field-label">Message Body
</div>
<textarea value={messageBody || ''} onChange={e => setMessageBody(e.target.value)}/>
</div>
</div>
<div className="col-md-12 col-sm-12 col-xs-12">
<button className="btn btn-default btn-sm float-right" onClick={() => redirectTo()}> Cancel </button>
<button className="btn btn-primary btn-sm float-right" onClick={() => saveMessage()}> Save </button>
</div>
</Tab>
</Tabs>
</div>
</div>
</>

View File

@ -1139,7 +1139,7 @@ const RoutesDashboard = () => {
className="me-2"
show={showDateDropdown}
onToggle={() => setShowDateDropdown(!showDateDropdown)}
autoClose="outside"
autoClose={false}
>
<Dropdown.Toggle variant="primary">
<CalendarWeek size={16} className="me-2"></CalendarWeek>Select Date to View Report
@ -1152,7 +1152,7 @@ const RoutesDashboard = () => {
className="me-2"
show={showFilterDropdown}
onToggle={() => setShowFilterDropdown(!showFilterDropdown)}
autoClose="outside"
autoClose={false}
>
<Dropdown.Toggle variant="primary">
<Filter size={16} className="me-2"></Filter>Filter