@visns-studio/visns-components 5.15.2 → 5.15.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,10 +9,14 @@ A comprehensive React component library used by the VISNS Studio team for CRM an
9
9
 
10
10
  VISNS Components is a React-based UI component library that provides a set of reusable, consistent, and customizable components for building web applications. It includes components for authentication, data grids, forms, navigation, and more, designed to work seamlessly together.
11
11
 
12
- ## Recent Updates (v5.15.1)
12
+ ## Recent Updates (v5.15.3)
13
13
 
14
14
  ### Latest Enhancements
15
15
 
16
+ - **Complete StandardModal Migration**: All components now use StandardModal instead of reactjs-popup for consistent modal behavior across the entire library
17
+ - **HTML Content Support**: Terms and conditions now properly parse HTML content from TinyMCE editors with clean rendering
18
+ - **Improved Typography**: Refined font sizing in Terms and Conditions to match page typography hierarchy
19
+ - **Modal Component Refactoring**: StandardModal converted to pure React implementation with enhanced accessibility and mobile support
16
20
  - **Enhanced JSON Table Field**: Improved json-table field type with better styling, user experience, and data editing capabilities
17
21
  - **Dynamic Action Labels**: GenericDetail component now supports dynamic action labels and custom action buttons for better user interaction
18
22
  - **Dependency Updates**: Updated lucide-react to version 0.536.0 for improved icon consistency and performance
@@ -3379,6 +3383,29 @@ npm run build
3379
3383
  yarn build
3380
3384
  ```
3381
3385
 
3386
+ ## Migration Notes
3387
+
3388
+ ### StandardModal Migration (v5.15.3) - COMPLETED
3389
+
3390
+ We have successfully migrated all components from `reactjs-popup` to our standardized `StandardModal` component for improved consistency and better user experience.
3391
+
3392
+ **All Migrations Completed ✅:**
3393
+ - ✅ **GenericQuote**: Updated to use StandardModal for form modals
3394
+ - ✅ **StandardModal**: Refactored to pure React implementation with enhanced accessibility
3395
+ - ✅ **Field.jsx**: Migrated 2 Popup instances (childFormShow and canvasPopupOpen)
3396
+ - ✅ **GenericFormBuilder.jsx**: Migrated 2 Popup instances (modalShow and modalFormShow)
3397
+ - ✅ **DropZone.jsx**: Migrated 1 Popup instance (modalShow)
3398
+ - ✅ **modals/GalleryModal.jsx**: Migrated 1 Popup instance (modalGalleryShow) with custom overlay styling
3399
+ - ✅ **QuickAction.jsx**: Migrated 1 Popup instance (modalShow)
3400
+ - ✅ **Call.jsx**: Migrated 1 Popup instance (modalShow)
3401
+
3402
+ **Benefits of StandardModal:**
3403
+ - Consistent modal behavior across all components
3404
+ - Better keyboard navigation and accessibility
3405
+ - Unified styling and responsive design
3406
+ - No external dependency on reactjs-popup
3407
+ - Enhanced mobile support with virtual keyboard accommodation
3408
+
3382
3409
  ## Contributing
3383
3410
 
3384
3411
  We welcome contributions! Please follow these steps:
@@ -3633,6 +3660,23 @@ All existing GenericQuote functionality remains unchanged:
3633
3660
 
3634
3661
  Proposal features are **opt-in** and activated only when `proposalConfig.enabled: true` is set.
3635
3662
 
3663
+ **Recent Improvements (v5.15.3 & 2025 Updates):**
3664
+ - **StandardModal Integration**: Replaced reactjs-popup with StandardModal for consistent modal behavior and better maintainability
3665
+ - **HTML Content Rendering**: Terms and conditions now support rich HTML content from TinyMCE editors with proper parsing via `html-react-parser`
3666
+ - **Typography Optimization**: Refined font sizing (14px desktop, 12px mobile) for better visual hierarchy and page consistency
3667
+ - **Enhanced Styling**: Improved CSS for HTML elements including lists, paragraphs, and formatted text in terms sections
3668
+ - **Complete Modal Consistency**: All modals throughout the library now use the same StandardModal component
3669
+
3670
+ **Latest 2025 Enhancements:**
3671
+ - **Enhanced Content Editor Modal**: Increased modal dimensions (98% width, 95% height) for better TinyMCE integration
3672
+ - **Streamlined Section Management**: Removed unnecessary section type selector from Edit Proposal Content modal
3673
+ - **Maximized Editor Space**: TinyMCE editor height increased from 400px to 500px with improved container sizing
3674
+ - **Dynamic Template Integration**: Template section titles now properly populate from backend configuration instead of hardcoded values
3675
+ - **Improved Content Flow**: Fixed proposal content insertion ensuring custom content appears correctly in generated PDFs
3676
+ - **Professional PDF Layout**: Enhanced margin handling with 40px/50px margins for all sections (except cover page preservation)
3677
+ - **Branding Color System**: Automatic application of branding profile colors (H1=primary, H2=secondary, H3=accent)
3678
+ - **Robust PDF Generation**: Improved error handling and blank page prevention during proposal PDF creation
3679
+
3636
3680
  **Advanced Usage Example:**
3637
3681
 
3638
3682
  ```jsx
package/package.json CHANGED
@@ -90,7 +90,7 @@
90
90
  "react-dom": "^17.0.0 || ^18.0.0"
91
91
  },
92
92
  "name": "@visns-studio/visns-components",
93
- "version": "5.15.2",
93
+ "version": "5.15.4",
94
94
  "description": "Various packages to assist in the development of our Custom Applications.",
95
95
  "main": "src/index.js",
96
96
  "files": [
@@ -1,5 +1,5 @@
1
1
  import React, { useState, useEffect } from "react";
2
- import Popup from "reactjs-popup";
2
+ import StandardModal from "./generic/StandardModal";
3
3
  import moment from "moment";
4
4
 
5
5
  import CustomFetch from "./Fetch";
@@ -124,12 +124,14 @@ function CallPop(props) {
124
124
  </button>
125
125
  </div>
126
126
  </div>
127
- <Popup
128
- open={modalShow}
127
+ <StandardModal
128
+ isOpen={modalShow}
129
129
  onClose={() => {
130
130
  setCallShow(false);
131
131
  setModalShow(false);
132
132
  }}
133
+ size="medium"
134
+ closeOnDocumentClick={false}
133
135
  >
134
136
  <div className="modalwrap">
135
137
  <div className="grid">
@@ -210,7 +212,7 @@ function CallPop(props) {
210
212
  </div>
211
213
  </div>
212
214
  </div>
213
- </Popup>
215
+ </StandardModal>
214
216
  </>
215
217
  ) : null}
216
218
  </>
@@ -15,7 +15,7 @@ import {
15
15
  } from 'lucide-react';
16
16
  import { toast } from 'react-toastify';
17
17
  import { arrayMoveImmutable } from 'array-move';
18
- import Popup from 'reactjs-popup';
18
+ import StandardModal from './generic/StandardModal';
19
19
  import imageCompression from 'browser-image-compression';
20
20
 
21
21
  import { confirmDialog } from './utils/ConfirmDialog';
@@ -637,9 +637,10 @@ function VisnsDropZone({ fetchData, files, settings, url, urlKey, deleteUrl, ent
637
637
  </div>
638
638
  ) : null}
639
639
  </div>
640
- <Popup
641
- open={modalShow}
640
+ <StandardModal
641
+ isOpen={modalShow}
642
642
  onClose={modalClose}
643
+ size="large"
643
644
  closeOnDocumentClick={false}
644
645
  >
645
646
  <div className={`${styles.modalwrap} top--modal`}>
@@ -704,7 +705,7 @@ function VisnsDropZone({ fetchData, files, settings, url, urlKey, deleteUrl, ent
704
705
  </div>
705
706
  </div>
706
707
  </div>
707
- </Popup>
708
+ </StandardModal>
708
709
  </>
709
710
  );
710
711
  }
@@ -6,7 +6,7 @@ import _ from 'lodash';
6
6
  import Toggle from 'react-toggle';
7
7
  import moment from 'moment';
8
8
  import parse from 'html-react-parser';
9
- import Popup from 'reactjs-popup';
9
+ import StandardModal from './generic/StandardModal';
10
10
  import { Sketch } from '@uiw/react-color';
11
11
  import { CopyToClipboard } from 'react-copy-to-clipboard';
12
12
  import { NumericFormat, PatternFormat } from 'react-number-format';
@@ -3095,12 +3095,11 @@ function Field({
3095
3095
  {renderFieldLabel()}
3096
3096
  </label>
3097
3097
  {renderAdditionalContainer()}
3098
- <Popup
3099
- open={childFormShow}
3098
+ <StandardModal
3099
+ isOpen={childFormShow}
3100
3100
  onClose={childFormClose}
3101
+ size="large"
3101
3102
  closeOnDocumentClick={false}
3102
- overlayStyle={{ zIndex: 10001 }}
3103
- contentStyle={{ zIndex: 10002 }}
3104
3103
  >
3105
3104
  <Form
3106
3105
  ajaxSetting={childForm.ajaxSetting}
@@ -3118,13 +3117,12 @@ function Field({
3118
3117
  updateForm={setChildForm}
3119
3118
  userProfile={userProfile}
3120
3119
  />
3121
- </Popup>
3122
- <Popup
3123
- open={canvasPopupOpen}
3120
+ </StandardModal>
3121
+ <StandardModal
3122
+ isOpen={canvasPopupOpen}
3124
3123
  onClose={() => setCanvasPopupOpen(false)}
3124
+ size="large"
3125
3125
  closeOnDocumentClick={false}
3126
- overlayStyle={{ zIndex: 10001 }}
3127
- contentStyle={{ zIndex: 10002 }}
3128
3126
  >
3129
3127
  <div className={`${styles.modalwrap} ${styles['top--modal']}`}>
3130
3128
  <div className={styles.modal}>
@@ -3240,7 +3238,7 @@ function Field({
3240
3238
  </div>
3241
3239
  </div>
3242
3240
  </div>
3243
- </Popup>
3241
+ </StandardModal>
3244
3242
  </div>
3245
3243
  );
3246
3244
  }
@@ -6,7 +6,7 @@ import React, {
6
6
  useMemo,
7
7
  } from 'react';
8
8
  import { useNavigate } from 'react-router-dom';
9
- import Popup from 'reactjs-popup';
9
+ import StandardModal from './generic/StandardModal';
10
10
  import { Search, X, Zap } from 'lucide-react';
11
11
 
12
12
  import CustomFetch from './Fetch';
@@ -408,20 +408,11 @@ const QuickAction = ({ setting }) => {
408
408
  </div>
409
409
  </div>
410
410
 
411
- <Popup
412
- open={modalShow}
411
+ <StandardModal
412
+ isOpen={modalShow}
413
413
  onClose={modalClose}
414
+ size="large"
414
415
  closeOnDocumentClick={false}
415
- contentStyle={{
416
- width: '80vw',
417
- maxWidth: '1200px',
418
- minWidth: '600px',
419
- padding: 0,
420
- border: 'none',
421
- borderRadius: '8px',
422
- overflow: 'hidden',
423
- maxHeight: '90vh',
424
- }}
425
416
  >
426
417
  <Form
427
418
  closeModal={modalClose}
@@ -431,7 +422,7 @@ const QuickAction = ({ setting }) => {
431
422
  columnId={formId}
432
423
  childDropdownCallback={childDropdownCallback}
433
424
  />
434
- </Popup>
425
+ </StandardModal>
435
426
  </>
436
427
  );
437
428
  };
@@ -2,7 +2,7 @@ import '../styles/global.css';
2
2
 
3
3
  import React, { useEffect, useRef, useState } from 'react';
4
4
  import { useParams } from 'react-router-dom';
5
- import Popup from 'reactjs-popup';
5
+ import StandardModal from './StandardModal';
6
6
  import { arrayMove } from '@dnd-kit/sortable';
7
7
  import {
8
8
  DndContext,
@@ -1222,12 +1222,12 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
1222
1222
  </div>
1223
1223
  </div>
1224
1224
 
1225
- <Popup
1226
- open={modalShow}
1225
+ <StandardModal
1226
+ isOpen={modalShow}
1227
1227
  onClose={handleCloseModal}
1228
+ size="medium"
1228
1229
  closeOnDocumentClick={false}
1229
1230
  >
1230
- {modalShow && <div className={styles.modalBackdrop} />}
1231
1231
  <div className={styles.modalwrap}>
1232
1232
  <div className={styles.modal}>
1233
1233
  <div className={styles.modal__header}>
@@ -2254,14 +2254,14 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
2254
2254
  </div>
2255
2255
  </div>
2256
2256
  </div>
2257
- </Popup>
2257
+ </StandardModal>
2258
2258
 
2259
- <Popup
2260
- open={modalFormShow}
2259
+ <StandardModal
2260
+ isOpen={modalFormShow}
2261
2261
  onClose={handleCloseModalForm}
2262
+ size="medium"
2262
2263
  closeOnDocumentClick={false}
2263
2264
  >
2264
- {modalFormShow && <div className={styles.modalBackdrop} />}
2265
2265
  <div className={styles.modalwrap}>
2266
2266
  <div className={styles.modal}>
2267
2267
  <div className={styles.modal__header}>
@@ -2308,7 +2308,7 @@ function GenericFormBuilder({ setting, urlParam, userProfile }) {
2308
2308
  </div>
2309
2309
  </div>
2310
2310
  </div>
2311
- </Popup>
2311
+ </StandardModal>
2312
2312
 
2313
2313
  {/* React Tooltips */}
2314
2314
  <Tooltip
@@ -2,11 +2,12 @@ import '../styles/global.css';
2
2
 
3
3
  import React, { useState, useEffect } from 'react';
4
4
  import { useParams, useNavigate } from 'react-router-dom';
5
- import Popup from 'reactjs-popup';
5
+ import StandardModal from './StandardModal';
6
6
  import moment from 'moment';
7
7
  import get from 'lodash/get';
8
8
  import { saveAs } from 'file-saver';
9
9
  import { toast } from 'react-toastify';
10
+ import parse from 'html-react-parser';
10
11
  import { arrayMoveImmutable } from 'array-move';
11
12
  import { showConfirmDialog } from './ConfirmationDialog';
12
13
  import { FileText, DollarSign, Clock, Eye, X, Edit3, FileEdit, Save, Settings } from 'lucide-react';
@@ -86,7 +87,6 @@ function GenericQuote({ logo, setting, urlParam, proposalConfig = null }) {
86
87
  // Content editor state
87
88
  const [showContentEditor, setShowContentEditor] = useState(false);
88
89
  const [proposalContent, setProposalContent] = useState('');
89
- const [contentSectionType, setContentSectionType] = useState('content');
90
90
 
91
91
  // Modal state variables
92
92
  const [modalShow, setModalShow] = useState(false);
@@ -1029,8 +1029,7 @@ function GenericQuote({ logo, setting, urlParam, proposalConfig = null }) {
1029
1029
  `/ajax/quotes/${data.id}/proposal-content`,
1030
1030
  'POST',
1031
1031
  {
1032
- content: proposalContent,
1033
- section_type: contentSectionType
1032
+ content: proposalContent
1034
1033
  }
1035
1034
  );
1036
1035
 
@@ -1569,22 +1568,6 @@ function GenericQuote({ logo, setting, urlParam, proposalConfig = null }) {
1569
1568
  </button>
1570
1569
  </div>
1571
1570
  <div className={styles.contentEditorBody}>
1572
- <div className={styles.editorSection}>
1573
- <label className={styles.editorLabel}>
1574
- <Settings size={16} />
1575
- Section Type:
1576
- <select
1577
- value={contentSectionType}
1578
- onChange={(e) => setContentSectionType(e.target.value)}
1579
- className={styles.sectionTypeSelect}
1580
- >
1581
- <option value="content">Content Section</option>
1582
- <option value="overview">Overview Section</option>
1583
- <option value="solution">Solution Section</option>
1584
- <option value="benefits">Benefits Section</option>
1585
- </select>
1586
- </label>
1587
- </div>
1588
1571
  <div className={styles.editorContainer}>
1589
1572
  <Editor
1590
1573
  apiKey="qagffr3pkuv17a8on1afax661irst1hbr4e6tbv888sz91jc"
@@ -1592,7 +1575,7 @@ function GenericQuote({ logo, setting, urlParam, proposalConfig = null }) {
1592
1575
  onEditorChange={handleContentChange}
1593
1576
  init={{
1594
1577
  height: '100%',
1595
- min_height: 400,
1578
+ min_height: 500,
1596
1579
  resize: false,
1597
1580
  menubar: true,
1598
1581
  plugins: [
@@ -1988,61 +1971,57 @@ function GenericQuote({ logo, setting, urlParam, proposalConfig = null }) {
1988
1971
  Terms and Conditions
1989
1972
  </h3>
1990
1973
  <div className={styles.termsContent}>
1991
- {data.terms_and_condition}
1974
+ {parse(data.terms_and_condition || '')}
1992
1975
  </div>
1993
1976
  </div>
1994
1977
  )}
1995
1978
  </div>
1996
1979
 
1997
1980
  {/* Form Modal */}
1998
- <Popup
1999
- open={modalShow}
1981
+ <StandardModal
1982
+ isOpen={modalShow}
2000
1983
  onClose={modalClose}
1984
+ size="large"
2001
1985
  closeOnDocumentClick={false}
2002
- contentStyle={{ width: '80vw', maxWidth: '1200px' }}
2003
1986
  >
2004
- <div className="modalwrap top--modal modalWide">
2005
- <div className="modal">
2006
- <Form
2007
- closeModal={modalClose}
2008
- columnId={formId}
2009
- fetchTable={() => {
2010
- // Reload the quote data after form submission
2011
- const fetchData = async () => {
2012
- if (
2013
- routeParams[urlParam] &&
2014
- routeParams[urlParam] > 0
2015
- ) {
2016
- try {
2017
- const res = await CustomFetch(
2018
- `${page.fetchUrl}/${routeParams[urlParam]}`,
2019
- 'GET',
2020
- {}
2021
- );
2022
- setData(res.data);
2023
- } catch (error) {
2024
- console.error(
2025
- 'Error fetching data:',
2026
- error
2027
- );
2028
- }
2029
- }
2030
- };
2031
- fetchData();
2032
- }}
2033
- formSettings={formData}
2034
- formType={formType}
2035
- style={form.style || {}}
2036
- updateForm={setFormData}
2037
- paramValue={
2038
- routeParams[urlParam]
2039
- ? routeParams[urlParam]
2040
- : 0
1987
+ <Form
1988
+ closeModal={modalClose}
1989
+ columnId={formId}
1990
+ fetchTable={() => {
1991
+ // Reload the quote data after form submission
1992
+ const fetchData = async () => {
1993
+ if (
1994
+ routeParams[urlParam] &&
1995
+ routeParams[urlParam] > 0
1996
+ ) {
1997
+ try {
1998
+ const res = await CustomFetch(
1999
+ `${page.fetchUrl}/${routeParams[urlParam]}`,
2000
+ 'GET',
2001
+ {}
2002
+ );
2003
+ setData(res.data);
2004
+ } catch (error) {
2005
+ console.error(
2006
+ 'Error fetching data:',
2007
+ error
2008
+ );
2009
+ }
2041
2010
  }
2042
- />
2043
- </div>
2044
- </div>
2045
- </Popup>
2011
+ };
2012
+ fetchData();
2013
+ }}
2014
+ formSettings={formData}
2015
+ formType={formType}
2016
+ style={form.style || {}}
2017
+ updateForm={setFormData}
2018
+ paramValue={
2019
+ routeParams[urlParam]
2020
+ ? routeParams[urlParam]
2021
+ : 0
2022
+ }
2023
+ />
2024
+ </StandardModal>
2046
2025
  </div>
2047
2026
  );
2048
2027
  }
@@ -1,5 +1,4 @@
1
- import React, { useState, useEffect } from 'react';
2
- import Popup from 'reactjs-popup';
1
+ import React, { useState, useEffect, useCallback } from 'react';
3
2
  import { X } from 'lucide-react';
4
3
  import formStyles from '../styles/Form.module.scss';
5
4
 
@@ -67,6 +66,37 @@ const StandardModal = ({
67
66
  window.addEventListener('resize', handleResize);
68
67
  return () => window.removeEventListener('resize', handleResize);
69
68
  }, []);
69
+
70
+ // Handle keyboard events
71
+ const handleKeyDown = useCallback((e) => {
72
+ if (!isOpen) return;
73
+
74
+ if (e.key === 'Escape' && closeOnEscape) {
75
+ onClose();
76
+ }
77
+ }, [isOpen, closeOnEscape, onClose]);
78
+
79
+ useEffect(() => {
80
+ if (isOpen) {
81
+ document.addEventListener('keydown', handleKeyDown);
82
+ document.body.style.overflow = 'hidden';
83
+ } else {
84
+ document.body.style.overflow = 'unset';
85
+ }
86
+
87
+ return () => {
88
+ document.removeEventListener('keydown', handleKeyDown);
89
+ document.body.style.overflow = 'unset';
90
+ };
91
+ }, [isOpen, handleKeyDown]);
92
+
93
+ // Handle backdrop click
94
+ const handleBackdropClick = (e) => {
95
+ if (closeOnDocumentClick && e.target === e.currentTarget) {
96
+ onClose();
97
+ }
98
+ };
99
+
70
100
  // Apply vertical alignment class if needed
71
101
  const getModalClasses = () => {
72
102
  let classes = formStyles.modal;
@@ -76,32 +106,47 @@ const StandardModal = ({
76
106
  return classes;
77
107
  };
78
108
 
79
- // Get size-based styles for the popup content with device-aware positioning
80
- const getContentStyle = () => {
109
+ // Get overlay styles
110
+ const getOverlayStyle = () => {
81
111
  const baseStyle = {
82
- ...customStyles.modal
112
+ position: 'fixed',
113
+ top: 0,
114
+ left: 0,
115
+ right: 0,
116
+ bottom: 0,
117
+ backgroundColor: 'rgba(0, 0, 0, 0.5)',
118
+ display: 'flex',
119
+ alignItems: verticalAlign === 'top' ? 'flex-start' : 'center',
120
+ justifyContent: 'center',
121
+ zIndex: 1000,
122
+ padding: '20px',
123
+ ...customStyles.overlay
83
124
  };
84
125
 
85
- // Device-specific positioning for virtual keyboard accommodation
86
- let positioningStyle = {};
87
- if (isMobile || isTablet) {
88
- // Position modal higher on mobile/tablet to accommodate virtual keyboard
89
- positioningStyle = {
90
- top: '5%', // Position higher (5% from top)
91
- left: '50%', // Center horizontally
92
- transform: 'translateX(-50%)', // Only center horizontally, no vertical transform
93
- maxHeight: '85vh', // Limit height to prevent overflow
94
- overflowY: 'auto', // Allow scrolling within modal if needed
95
- position: 'fixed' // Ensure fixed positioning for proper centering
96
- };
126
+ if (verticalAlign === 'top') {
127
+ baseStyle.paddingTop = '5%';
97
128
  }
98
129
 
130
+ return baseStyle;
131
+ };
132
+
133
+ // Get size-based styles for the modal content with device-aware positioning
134
+ const getContentStyle = () => {
135
+ const baseStyle = {
136
+ position: 'relative',
137
+ backgroundColor: 'white',
138
+ borderRadius: '8px',
139
+ boxShadow: '0 10px 30px rgba(0, 0, 0, 0.3)',
140
+ maxHeight: isMobile || isTablet ? '85vh' : '90vh',
141
+ overflowY: 'auto',
142
+ ...customStyles.modal
143
+ };
144
+
99
145
  // Apply size-based styles with device considerations
100
146
  switch (size) {
101
147
  case 'small':
102
148
  return {
103
149
  ...baseStyle,
104
- ...positioningStyle,
105
150
  width: isMobile ? '95vw' : '400px',
106
151
  minWidth: isMobile ? '300px' : '400px',
107
152
  maxWidth: isMobile ? '95vw' : '600px'
@@ -109,7 +154,6 @@ const StandardModal = ({
109
154
  case 'large':
110
155
  return {
111
156
  ...baseStyle,
112
- ...positioningStyle,
113
157
  width: '95vw',
114
158
  minWidth: isMobile ? '300px' : '800px',
115
159
  maxWidth: isMobile ? '95vw' : '1600px'
@@ -118,51 +162,55 @@ const StandardModal = ({
118
162
  default:
119
163
  return {
120
164
  ...baseStyle,
121
- ...positioningStyle,
122
- width: isMobile ? '95vw' : '90vw',
165
+ width: isMobile ? '95vw' : '80vw',
123
166
  minWidth: isMobile ? '300px' : '600px',
124
- maxWidth: isMobile ? '95vw' : '1400px'
167
+ maxWidth: isMobile ? '95vw' : '1200px'
125
168
  };
126
169
  }
127
170
  };
128
171
 
172
+ if (!isOpen) {
173
+ return null;
174
+ }
175
+
129
176
  return (
130
- <Popup
131
- open={isOpen}
132
- onClose={onClose}
133
- modal
134
- closeOnDocumentClick={closeOnDocumentClick}
135
- closeOnEscape={closeOnEscape}
136
- contentStyle={getContentStyle()}
177
+ <div
178
+ style={getOverlayStyle()}
179
+ onClick={handleBackdropClick}
137
180
  >
138
- <div className={formStyles.modalwrap}>
139
- <div
140
- className={getModalClasses()}
141
- >
142
- {showHeader && (
143
- <div className={formStyles.modal__header} style={customStyles.header}>
144
- <h1 style={customStyles.title}>{title}</h1>
145
- <button
146
- className={formStyles.modal__close}
147
- onClick={onClose}
148
- style={customStyles.closeButton}
149
- type="button"
150
- aria-label="Close modal"
151
- >
152
- <X strokeWidth={1} size={24} />
153
- </button>
154
- </div>
155
- )}
156
- {showHeader ? (
157
- <div className={formStyles.modal__content} style={customStyles.content}>
158
- {children}
159
- </div>
160
- ) : (
161
- children
162
- )}
181
+ <div
182
+ style={getContentStyle()}
183
+ onClick={(e) => e.stopPropagation()}
184
+ >
185
+ <div className={formStyles.modalwrap}>
186
+ <div
187
+ className={getModalClasses()}
188
+ >
189
+ {showHeader && (
190
+ <div className={formStyles.modal__header} style={customStyles.header}>
191
+ <h1 style={customStyles.title}>{title}</h1>
192
+ <button
193
+ className={formStyles.modal__close}
194
+ onClick={onClose}
195
+ style={customStyles.closeButton}
196
+ type="button"
197
+ aria-label="Close modal"
198
+ >
199
+ <X strokeWidth={1} size={24} />
200
+ </button>
201
+ </div>
202
+ )}
203
+ {showHeader ? (
204
+ <div className={formStyles.modal__content} style={customStyles.content}>
205
+ {children}
206
+ </div>
207
+ ) : (
208
+ children
209
+ )}
210
+ </div>
163
211
  </div>
164
212
  </div>
165
- </Popup>
213
+ </div>
166
214
  );
167
215
  };
168
216
 
@@ -1,5 +1,5 @@
1
1
  import { useState } from 'react';
2
- import Popup from 'reactjs-popup';
2
+ import StandardModal from '../generic/StandardModal';
3
3
  import { toast } from 'react-toastify';
4
4
  import imageCompression from 'browser-image-compression';
5
5
  // import Vapor from 'laravel-vapor'; // Commented out to avoid build issues
@@ -169,22 +169,15 @@ const GalleryModal = ({
169
169
 
170
170
  return (
171
171
  <>
172
- <Popup
173
- open={modalGalleryShow}
172
+ <StandardModal
173
+ isOpen={modalGalleryShow}
174
174
  onClose={modalGalleryClose}
175
+ size="large"
175
176
  closeOnDocumentClick={false}
176
- contentStyle={{
177
- width: '90vw',
178
- maxWidth: '1400px',
179
- minWidth: '600px',
180
- padding: 0,
181
- border: 'none',
182
- borderRadius: '8px',
183
- overflow: 'hidden',
184
- maxHeight: '90vh',
185
- }}
186
- overlayStyle={{
187
- backgroundColor: 'rgba(0, 0, 0, 0.7)',
177
+ customStyles={{
178
+ overlay: {
179
+ backgroundColor: 'rgba(0, 0, 0, 0.7)'
180
+ }
188
181
  }}
189
182
  >
190
183
  <div className={styles.modalwrap}>
@@ -390,7 +383,7 @@ const GalleryModal = ({
390
383
  </div>
391
384
  </div>
392
385
  </div>
393
- </Popup>
386
+ </StandardModal>
394
387
 
395
388
  {/* Lightbox for full-size image viewing */}
396
389
  <Lightbox
@@ -246,10 +246,10 @@
246
246
  background: white;
247
247
  border-radius: 12px;
248
248
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.2);
249
- width: 95%;
250
- max-width: 1400px;
251
- height: 90vh;
252
- max-height: 90vh;
249
+ width: 98%;
250
+ max-width: 1600px;
251
+ height: 95vh;
252
+ max-height: 95vh;
253
253
  display: flex;
254
254
  flex-direction: column;
255
255
  overflow: hidden;
@@ -313,7 +313,7 @@
313
313
 
314
314
  .contentEditorBody {
315
315
  flex: 1;
316
- padding: 20px;
316
+ padding: 12px;
317
317
  overflow: hidden;
318
318
  background: var(--tertiary-color);
319
319
  display: flex;
@@ -374,7 +374,8 @@
374
374
  flex: 1; /* Take all remaining space */
375
375
  display: flex;
376
376
  flex-direction: column;
377
- min-height: 0; /* Allow flex shrinking */
377
+ min-height: 500px; /* Ensure minimum height for editor */
378
+ height: 100%; /* Fill available height */
378
379
 
379
380
  /* TinyMCE overrides */
380
381
  :global(.tox-tinymce) {
@@ -1061,10 +1062,49 @@
1061
1062
  }
1062
1063
 
1063
1064
  .termsContent {
1064
- font-size: 0.9rem;
1065
- line-height: 1.6;
1065
+ font-size: 14px;
1066
+ line-height: 1.4;
1066
1067
  color: var(--paragraph-color);
1067
- white-space: pre-wrap;
1068
+
1069
+ /* Reset styles to avoid conflicts with TinyMCE HTML content */
1070
+ white-space: normal;
1071
+
1072
+ /* Basic styling for TinyMCE HTML elements */
1073
+ ul, ol {
1074
+ margin: 8px 0;
1075
+ padding-left: 20px;
1076
+ }
1077
+
1078
+ li {
1079
+ margin: 4px 0;
1080
+ padding: 0;
1081
+ }
1082
+
1083
+ p {
1084
+ margin: 8px 0;
1085
+ }
1086
+
1087
+ strong, b {
1088
+ font-weight: 600;
1089
+ }
1090
+
1091
+ em, i {
1092
+ font-style: italic;
1093
+ }
1094
+
1095
+ /* Remove excessive spacing from nested elements */
1096
+ ul ul, ol ol, ul ol, ol ul {
1097
+ margin: 2px 0;
1098
+ }
1099
+
1100
+ /* Ensure proper spacing for the first and last elements */
1101
+ > *:first-child {
1102
+ margin-top: 0;
1103
+ }
1104
+
1105
+ > *:last-child {
1106
+ margin-bottom: 0;
1107
+ }
1068
1108
  }
1069
1109
 
1070
1110
  .quoteTableSection {
@@ -1387,7 +1427,7 @@
1387
1427
  }
1388
1428
 
1389
1429
  .termsContent {
1390
- font-size: 0.85rem;
1391
- line-height: 1.5;
1430
+ font-size: 12px;
1431
+ line-height: 1.3;
1392
1432
  }
1393
1433
  }