Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

# dependencies
/node_modules
package-lock.json
# testing
/coverage
*.code-snippets
Expand All @@ -28,9 +27,9 @@ yarn-error.log*
/.idea

.vscode/launch.json
.vscode/settings.json

**\ **

/public/tinymce/
package-lock.json
/public/tinymce/Community/
Community/
public/tinymce/
146 changes: 142 additions & 4 deletions public/index.css
Original file line number Diff line number Diff line change
@@ -1,18 +1,41 @@
html {
min-height: 100vh !important;
}

body {
min-height: 100vh !important;
}
body.dark-mode,
body.dark-mode #root {
background-color: #1a1d23 !important;
}

body:not(.dark-mode),
body:not(.dark-mode) #root {
background-color: #ffffff !important;
}

body.bm-dashboard-dark {
background-color: #1a1d23 !important;
color: #ffffff !important;
min-height: 100vh !important;
}


/* public/index.css */

/* Global Dark Mode Styles */
body.dark-mode,
body.bm-dashboard-dark {
background-color: #1b2a41 !important;
background-color: #1a1d23 !important;
color: #ffffff !important;
}

body.dark-mode #root,
body.bm-dashboard-dark #root {
background-color: #1b2a41 !important;
background-color: #1a1d23 !important;
color: #ffffff !important;
}

/* Enhanced text visibility for dark mode */
body.dark-mode *,
body.bm-dashboard-dark * {
Expand Down Expand Up @@ -335,4 +358,119 @@ body.bm-dashboard-dark .page-item.active .page-link {
/* Hide the horizontal scrollbar */
.container-fluid::-webkit-scrollbar {
display: none;
}
}

/* TinyMCE "Get all features" button - force dark text */
.tox-promotion-link,
.tox-promotion a {
color: #000000 !important;
background-color: #f0f0f0 !important;
padding: 4px 8px !important;
border-radius: 4px !important;
}

body.dark-mode .tox-promotion-link,
body.dark-mode .tox-promotion a {
color: #ffffff !important;
background-color: #374151 !important;
}
body.dark-mode.bm-dashboard-dark > #root > .bg-oxford-blue {
background-color: #1a1d23 !important;
}

/* Fix orange/beige side panels */
body.dark-mode.bm-dashboard-dark {
background-color: #1a1d23 !important;
}

body.dark-mode.bm-dashboard-dark > #root {
background-color: #1a1d23 !important;
}
/* Fix tab-pane side background */
body.dark-mode .tab-pane.active {
background-color: #1a1d23 !important;
}

body:not(.dark-mode) .tab-pane.active {
background-color: #f8f9fa !important;
}

/* ===== EMAIL TEMPLATES PAGE FIXES ===== */

/* Fix beige thead */
body.dark-mode .email-template-list table thead tr th {
background-color: #374151 !important;
color: #e9ecef !important;
border-color: #4a5568 !important;
}

/* Fix action buttons - all 3 on one row */
body.dark-mode .email-template-list .action-buttons,
body:not(.dark-mode) .email-template-list .action-buttons {
display: flex !important;
flex-direction: row !important;
flex-wrap: nowrap !important;
align-items: center !important;
gap: 6px !important;
}

body.dark-mode .email-template-list .action-buttons .btn,
body:not(.dark-mode) .email-template-list .action-buttons .btn {
width: 30px !important;
height: 30px !important;
padding: 0 !important;
margin: 0 !important;
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
flex-shrink: 0 !important;
}
/* Fix search icon inside search box */
body .email-template-list .search-container {
position: relative !important;
}

body .email-template-list .search-container svg {
position: absolute !important;
left: 0.65rem !important;
top: 50% !important;
transform: translateY(-50%) !important;
z-index: 5 !important;
pointer-events: none !important;
}

body .email-template-list .search-container input {
padding-left: 2.25rem !important;
}

/* Fix info button - purple */
body .email-template-list .action-btn.info-btn {
background-color: #6f42c1 !important;
color: #ffffff !important;
border-color: #6f42c1 !important;
}

/* Fix edit button - orange */
body .email-template-list .action-btn.edit-btn {
background-color: #fd7e14 !important;
color: #ffffff !important;
border-color: #fd7e14 !important;
}

/* Fix delete button - red */
body .email-template-list .action-btn.delete-btn {
background-color: #dc3545 !important;
color: #ffffff !important;
border-color: #dc3545 !important;
}

/* Fix alert-warning dark mode globally */
body.dark-mode .modal .alert-warning {
background-color: #92400e !important;
border-color: #d97706 !important;
color: #fef3c7 !important;
}

body.dark-mode .modal .alert-warning * {
color: #fef3c7 !important;
}
7 changes: 7 additions & 0 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>HGN APP</title>
<style>
html, body {
background-color: #1a1d23 !important;
margin: 0 !important;
padding: 0 !important;
}
</style>
</head>

<body>
Expand Down
33 changes: 32 additions & 1 deletion src/App.module.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@


html {
overflow-x: hidden;
}
Expand All @@ -14,10 +16,23 @@
height: 100%;
overflow-x: auto;
overflow-y: hidden;
/* background-color: var(--background-color); */
background-color: #ffffff;
}

html {
background-color: #1a1d23 !important;
}

body {

Check warning on line 26 in src/App.module.css

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Unexpected duplicate selector "body", first used at line 7

See more on https://sonarcloud.io/project/issues?id=OneCommunityGlobal_HighestGoodNetworkApp&issues=AZ1g4uG27Pzve-iuCyjM&open=AZ1g4uG27Pzve-iuCyjM&pullRequest=5112
background-color: #1a1d23 !important;
}

/* Dark mode override for #root */
body.dark-mode #root,
body.bm-dashboard-dark #root {
background-color: #1a1d23 !important;
}

.App {
text-align: center;
}
Expand Down Expand Up @@ -280,3 +295,19 @@
gap: 24px;
padding: 20px;
}

/* Global dark mode background fix - NUCLEAR OPTION */
body.dark-mode #root {
background-color: #1a1d23 !important;
}

body.dark-mode .bg-oxford-blue,
body.dark-mode div[class*="bg-oxford-blue"],
body.dark-mode .text-light {
background-color: #1a1d23 !important;
}

/* Override ANY inline styles */
body.dark-mode [style*="background"] {
background-color: #1a1d23 !important;
}
85 changes: 85 additions & 0 deletions src/actions/emailOutboxActions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import httpService from '../services/httpService';
import { toast } from 'react-toastify';

// Action Types
// Note: EMAIL = parent Email record, EMAIL_BATCH = child EmailBatch item
export const EMAIL_OUTBOX_ACTIONS = {
FETCH_EMAILS_START: 'FETCH_EMAILS_START',
FETCH_EMAILS_SUCCESS: 'FETCH_EMAILS_SUCCESS',
FETCH_EMAILS_ERROR: 'FETCH_EMAILS_ERROR',
};

// Fetch emails (parent Email records) - Outbox list
// Backend returns: { success: true, data: emails[] }
export const fetchEmails = () => async (dispatch) => {
try {
dispatch({ type: EMAIL_OUTBOX_ACTIONS.FETCH_EMAILS_START });

const response = await httpService.get('/api/email-outbox');

if (response.data.success) {
// Backend returns data as array directly
const emails = Array.isArray(response.data.data) ? response.data.data : [];

dispatch({
type: EMAIL_OUTBOX_ACTIONS.FETCH_EMAILS_SUCCESS,
payload: emails,
});

return emails;
} else {
throw new Error(response.data.message || 'Failed to fetch emails');
}
} catch (error) {
const errorMessage = error.response?.data?.message || error.message || 'Failed to fetch emails';
dispatch({
type: EMAIL_OUTBOX_ACTIONS.FETCH_EMAILS_ERROR,
payload: errorMessage,
});
toast.error(errorMessage);
throw error;
}
};

// Resend email with selected recipient option
// Backend endpoint: POST /api/resend-email
// Backend returns: { success: true, message: '...', data: { emailId: '...', recipientCount: ... } }
export const resendEmail = (emailId, recipientOption, specificRecipients = []) => async (dispatch, getState) => {
try {
// Get current user for requestor (required by backend)
const state = getState();
const currentUser = state.auth?.user;

if (!currentUser || !currentUser.userid) {
throw new Error('User authentication required to resend emails');
}

const requestor = {
requestorId: currentUser.userid,
email: currentUser.email,
role: currentUser.role,
};

const response = await httpService.post('/api/resend-email', {
emailId,
recipientOption,
specificRecipients: Array.isArray(specificRecipients) ? specificRecipients : [],
requestor,
});

if (response.data.success) {
const message = response.data.message || 'Email created for resend successfully. Processing started.';
toast.success(message);
// Refresh the emails list
await dispatch(fetchEmails());
return response.data.data;
} else {
throw new Error(response.data.message || 'Failed to resend email');
}
} catch (error) {
const errorMessage = error.response?.data?.message || error.message || 'Failed to resend email';
toast.error(errorMessage);
throw error;
}
};

Loading
Loading