@visns-studio/visns-components 5.7.7 → 5.7.8
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/package.json +2 -2
- package/src/components/crm/generic/ActionButtons.jsx +22 -0
- package/src/components/crm/generic/GenericQuote.jsx +278 -152
- package/src/components/crm/generic/styles/ActionButtons.module.scss +65 -0
- package/src/components/crm/generic/styles/GenericQuote.module.scss +425 -130
- package/src/components/crm/generic/utils/formatters.js +43 -0
package/package.json
CHANGED
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"reactjs-popup": "^2.0.6",
|
|
55
55
|
"style-loader": "^4.0.0",
|
|
56
56
|
"swapy": "^1.0.5",
|
|
57
|
-
"sweetalert2": "^11.
|
|
57
|
+
"sweetalert2": "^11.20.0",
|
|
58
58
|
"truncate": "^3.0.0",
|
|
59
59
|
"uuid": "^11.1.0",
|
|
60
60
|
"validator": "^13.15.0",
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"react-dom": "^17.0.0 || ^18.0.0"
|
|
83
83
|
},
|
|
84
84
|
"name": "@visns-studio/visns-components",
|
|
85
|
-
"version": "5.7.
|
|
85
|
+
"version": "5.7.8",
|
|
86
86
|
"description": "Various packages to assist in the development of our Custom Applications.",
|
|
87
87
|
"main": "src/index.js",
|
|
88
88
|
"files": [
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import styles from './styles/ActionButtons.module.scss';
|
|
3
|
+
|
|
4
|
+
function ActionButtons({ actions, onActionClick }) {
|
|
5
|
+
return (
|
|
6
|
+
<div className={styles.actionButtons}>
|
|
7
|
+
{actions &&
|
|
8
|
+
actions.map((action) => (
|
|
9
|
+
<button
|
|
10
|
+
key={`action-${action.id}`}
|
|
11
|
+
className={styles.actionButton}
|
|
12
|
+
onClick={() => onActionClick(action.id)}
|
|
13
|
+
title={action.label}
|
|
14
|
+
>
|
|
15
|
+
{action.label}
|
|
16
|
+
</button>
|
|
17
|
+
))}
|
|
18
|
+
</div>
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export default ActionButtons;
|
|
@@ -1,35 +1,29 @@
|
|
|
1
1
|
import '../../styles/global.css';
|
|
2
2
|
|
|
3
3
|
import React, { useState, useEffect } from 'react';
|
|
4
|
-
import {
|
|
4
|
+
import { useParams } from 'react-router-dom';
|
|
5
5
|
import moment from 'moment';
|
|
6
6
|
import get from 'lodash/get';
|
|
7
7
|
|
|
8
|
-
import Breadcrumb from '../../crm/Breadcrumb';
|
|
9
8
|
import CustomFetch from '../../crm/Fetch';
|
|
10
|
-
import
|
|
11
|
-
import
|
|
9
|
+
import ActionButtons from './ActionButtons';
|
|
10
|
+
import { formatCurrency } from './utils/formatters';
|
|
12
11
|
|
|
13
12
|
import styles from './styles/GenericQuote.module.scss';
|
|
14
13
|
|
|
15
|
-
function GenericQuote({
|
|
16
|
-
extraUrlParam,
|
|
17
|
-
layout = 'full',
|
|
18
|
-
setting,
|
|
19
|
-
setActiveNav = null,
|
|
20
|
-
urlParam,
|
|
21
|
-
userProfile,
|
|
22
|
-
}) {
|
|
14
|
+
function GenericQuote({ logo, setting, urlParam }) {
|
|
23
15
|
const routeParams = useParams();
|
|
24
16
|
|
|
25
|
-
const {
|
|
17
|
+
const { actions: actionItems, page, tables } = setting;
|
|
26
18
|
|
|
27
19
|
const [data, setData] = useState({});
|
|
28
|
-
const [
|
|
20
|
+
const [actions, setActions] = useState(actionItems || []);
|
|
29
21
|
|
|
30
22
|
useEffect(() => {
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
if (actionItems && actionItems.length > 0) {
|
|
24
|
+
setActions(actionItems);
|
|
25
|
+
}
|
|
26
|
+
}, [actionItems]);
|
|
33
27
|
|
|
34
28
|
useEffect(() => {
|
|
35
29
|
const fetchData = async () => {
|
|
@@ -50,177 +44,309 @@ function GenericQuote({
|
|
|
50
44
|
fetchData();
|
|
51
45
|
}, [routeParams['*']]);
|
|
52
46
|
|
|
47
|
+
const handleActionClick = (actionId) => {
|
|
48
|
+
// Handle different actions based on actionId
|
|
49
|
+
switch (actionId) {
|
|
50
|
+
case 'addItem':
|
|
51
|
+
// Handle add item action
|
|
52
|
+
console.log('Add item clicked');
|
|
53
|
+
break;
|
|
54
|
+
case 'editQuote':
|
|
55
|
+
// Handle edit quote action
|
|
56
|
+
console.log('Edit quote clicked');
|
|
57
|
+
break;
|
|
58
|
+
case 'viewTicket':
|
|
59
|
+
// Handle view ticket action
|
|
60
|
+
console.log('View ticket clicked');
|
|
61
|
+
break;
|
|
62
|
+
case 'saveAsPdf':
|
|
63
|
+
// Handle save as PDF action
|
|
64
|
+
console.log('Save as PDF clicked');
|
|
65
|
+
break;
|
|
66
|
+
case 'saveToTicket':
|
|
67
|
+
// Handle save to ticket action
|
|
68
|
+
console.log('Save to ticket clicked');
|
|
69
|
+
break;
|
|
70
|
+
default:
|
|
71
|
+
console.log(`Action ${actionId} clicked`);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
53
75
|
return (
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
76
|
+
<div className={styles.quoteWrapper}>
|
|
77
|
+
{/* Top section with quote number and action buttons */}
|
|
78
|
+
<div className={styles.quoteTopSection}>
|
|
79
|
+
<div className={styles.quoteIdentifier}>
|
|
80
|
+
<h1 className={styles.quoteTitle}>
|
|
81
|
+
Quote
|
|
82
|
+
<span className={styles.quoteNumber}>
|
|
83
|
+
#{data.id || ''}
|
|
84
|
+
</span>
|
|
85
|
+
</h1>
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
{/* Action buttons */}
|
|
89
|
+
<div className={styles.actionButtonsContainer}>
|
|
90
|
+
<ActionButtons
|
|
91
|
+
actions={actions}
|
|
92
|
+
onActionClick={handleActionClick}
|
|
93
|
+
/>
|
|
60
94
|
</div>
|
|
61
95
|
</div>
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
96
|
+
|
|
97
|
+
{/* Quote status banner */}
|
|
98
|
+
<div className={styles.quotestatus}>
|
|
99
|
+
<div className={styles.statusLeft}>
|
|
100
|
+
<span
|
|
101
|
+
className={
|
|
102
|
+
styles[
|
|
103
|
+
'q__' +
|
|
104
|
+
(data.status
|
|
105
|
+
? data.status.name.toLowerCase()
|
|
106
|
+
: '')
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
>
|
|
110
|
+
{data.status ? data.status.name : ''}
|
|
111
|
+
{data.task && data.task.ticket_id && (
|
|
112
|
+
<span className={styles.ticketId}>
|
|
113
|
+
- #{data.task.ticket_id}
|
|
114
|
+
</span>
|
|
115
|
+
)}
|
|
116
|
+
</span>
|
|
117
|
+
</div>
|
|
118
|
+
<div className={styles.statusRight}>
|
|
119
|
+
{data.label && (
|
|
120
|
+
<span className={styles.quoteReference}>
|
|
121
|
+
{data.label}
|
|
122
|
+
</span>
|
|
123
|
+
)}
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
{/* Quote content */}
|
|
128
|
+
<div className={styles.quoteContent}>
|
|
129
|
+
{/* Quote header with logo and date */}
|
|
130
|
+
<div className={styles.quoteHeaderSection}>
|
|
131
|
+
<div className={styles.quoteLogoContainer}>
|
|
132
|
+
<img
|
|
133
|
+
src={logo}
|
|
134
|
+
alt="Company Logo"
|
|
135
|
+
className={styles.quoteLogo}
|
|
136
|
+
/>
|
|
66
137
|
</div>
|
|
67
|
-
<div className={styles.
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
: '')
|
|
77
|
-
]
|
|
78
|
-
}
|
|
79
|
-
>
|
|
80
|
-
{data.status ? data.status.name : ''} - #
|
|
81
|
-
{data.task ? data.task.ticket_id : ''}
|
|
82
|
-
</span>
|
|
83
|
-
</div>
|
|
138
|
+
<div className={styles.quoteTitleContainer}>
|
|
139
|
+
<h2 className={styles.quoteBigNumber}>
|
|
140
|
+
Quote #{data.id || ''}
|
|
141
|
+
</h2>
|
|
142
|
+
<div className={styles.quoteDate}>
|
|
143
|
+
<strong>Date:</strong>{' '}
|
|
144
|
+
{data.created_at
|
|
145
|
+
? moment(data.created_at).format('DD-MM-YYYY')
|
|
146
|
+
: ''}
|
|
84
147
|
</div>
|
|
85
|
-
|
|
86
|
-
|
|
148
|
+
</div>
|
|
149
|
+
</div>
|
|
150
|
+
|
|
151
|
+
{/* Quote parties */}
|
|
152
|
+
<div className={styles.quoteParties}>
|
|
153
|
+
<div className={styles.quoteParty}>
|
|
154
|
+
<h3 className={styles.partyTitle}>Quote To:</h3>
|
|
155
|
+
<div className={styles.partyDetails}>
|
|
156
|
+
{data.customer ? data.customer.name : ''}
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
<div className={styles.quoteParty}>
|
|
160
|
+
<h3 className={styles.partyTitle}>Quote From:</h3>
|
|
161
|
+
<div className={styles.partyDetails}>
|
|
162
|
+
Visns Studio
|
|
163
|
+
<br />
|
|
164
|
+
660C Newcastle Street
|
|
165
|
+
<br />
|
|
166
|
+
Leederville, WA, 6007
|
|
167
|
+
<br />
|
|
168
|
+
08 6383 6600
|
|
169
|
+
<br />
|
|
170
|
+
team@visns.studio
|
|
171
|
+
<br />
|
|
172
|
+
ABN: 41 994 317 718
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
</div>
|
|
176
|
+
|
|
177
|
+
{/* Quote items tables */}
|
|
178
|
+
<div className={styles.quoteItems}>
|
|
179
|
+
{tables.length > 0 &&
|
|
180
|
+
tables.map((table) => {
|
|
181
|
+
// Only show tables that have entries
|
|
182
|
+
if (
|
|
183
|
+
!data[table.id] ||
|
|
184
|
+
data[table.id].length === 0
|
|
185
|
+
) {
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Calculate subtotal for this table
|
|
190
|
+
const subtotal = table.total
|
|
191
|
+
? parseFloat(table.total)
|
|
192
|
+
: data[table.id].reduce((sum, row) => {
|
|
193
|
+
// Make sure we're parsing numbers correctly
|
|
194
|
+
let total;
|
|
195
|
+
if (typeof row.total === 'number') {
|
|
196
|
+
total = row.total;
|
|
197
|
+
} else if (row.total) {
|
|
198
|
+
total = parseFloat(
|
|
199
|
+
String(row.total).replace(
|
|
200
|
+
/[^0-9.-]+/g,
|
|
201
|
+
''
|
|
202
|
+
)
|
|
203
|
+
);
|
|
204
|
+
} else if (row.rate && row.qty) {
|
|
205
|
+
// If total is not available, calculate from rate and qty
|
|
206
|
+
const rate = parseFloat(
|
|
207
|
+
String(row.rate).replace(
|
|
208
|
+
/[^0-9.-]+/g,
|
|
209
|
+
''
|
|
210
|
+
)
|
|
211
|
+
);
|
|
212
|
+
const qty = parseFloat(
|
|
213
|
+
String(row.qty).replace(
|
|
214
|
+
/[^0-9.-]+/g,
|
|
215
|
+
''
|
|
216
|
+
)
|
|
217
|
+
);
|
|
218
|
+
total = rate * qty;
|
|
219
|
+
} else {
|
|
220
|
+
total = 0;
|
|
221
|
+
}
|
|
222
|
+
return sum + (isNaN(total) ? 0 : total);
|
|
223
|
+
}, 0);
|
|
224
|
+
|
|
225
|
+
// We're using the imported formatCurrency function
|
|
226
|
+
|
|
227
|
+
return (
|
|
87
228
|
<div
|
|
88
|
-
|
|
229
|
+
key={`table-section-${table.id}`}
|
|
230
|
+
className={styles.quoteTableSection}
|
|
89
231
|
>
|
|
90
|
-
<
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
alt="Visns Studio Quote"
|
|
94
|
-
/>
|
|
95
|
-
</span>
|
|
96
|
-
</div>
|
|
97
|
-
<div className={styles.qitem__half}>
|
|
98
|
-
<div className={styles.qtitle}>
|
|
99
|
-
Quote #{data.id || ''}
|
|
100
|
-
</div>
|
|
101
|
-
</div>
|
|
102
|
-
</div>
|
|
103
|
-
<div className={styles.qitem}>
|
|
104
|
-
<div className={styles.qitem__half}>
|
|
105
|
-
<div className={styles.qdate}>
|
|
106
|
-
<strong>Date:</strong>{' '}
|
|
107
|
-
{data.created_at
|
|
108
|
-
? moment(data.created_at).format(
|
|
109
|
-
'DD-MM-YYYY'
|
|
110
|
-
)
|
|
111
|
-
: ''}
|
|
112
|
-
</div>
|
|
113
|
-
</div>
|
|
114
|
-
<div className={styles.qitem__half}>
|
|
115
|
-
<div className={styles.qno}>
|
|
116
|
-
<strong>{data.label}</strong>
|
|
117
|
-
</div>
|
|
118
|
-
</div>
|
|
119
|
-
</div>
|
|
120
|
-
<div className={styles.qitem}>
|
|
121
|
-
<div className={styles.qitem__half}>
|
|
122
|
-
<div className={styles.qdetails}>
|
|
123
|
-
<p style={{ margin: 0 }}>
|
|
124
|
-
<strong>Quote To:</strong>
|
|
125
|
-
<br />
|
|
126
|
-
{data.customer
|
|
127
|
-
? data.customer.name
|
|
128
|
-
: ''}
|
|
129
|
-
</p>
|
|
130
|
-
</div>
|
|
131
|
-
</div>
|
|
132
|
-
<div className={styles.qitem__half}>
|
|
133
|
-
<div className={styles.qvisns}>
|
|
134
|
-
<p style={{ margin: 0 }}>
|
|
135
|
-
<strong>Quote From:</strong>
|
|
136
|
-
<br />
|
|
137
|
-
Visns Studio
|
|
138
|
-
<br />
|
|
139
|
-
660C Newcastle Street
|
|
140
|
-
<br />
|
|
141
|
-
Leederville, WA, 6007
|
|
142
|
-
<br />
|
|
143
|
-
08 6383 6600
|
|
144
|
-
<br />
|
|
145
|
-
team@visns.studio
|
|
146
|
-
<br />
|
|
147
|
-
ABN: 41 994 317 718
|
|
148
|
-
</p>
|
|
149
|
-
</div>
|
|
150
|
-
</div>
|
|
151
|
-
</div>
|
|
152
|
-
</div>
|
|
153
|
-
<div className={styles.qitem}>
|
|
154
|
-
{tables.length > 0 &&
|
|
155
|
-
tables.map((table) => (
|
|
232
|
+
<h2 className={styles.tableTitle}>
|
|
233
|
+
{table.label}
|
|
234
|
+
</h2>
|
|
156
235
|
<table
|
|
157
|
-
key={`table-${table.id}`}
|
|
158
|
-
className={
|
|
236
|
+
key={`table-${table.id}`}
|
|
237
|
+
className={styles.quoteTable}
|
|
159
238
|
>
|
|
160
239
|
<thead>
|
|
161
|
-
<tr className={styles.splitheader}>
|
|
162
|
-
<th colSpan="8">
|
|
163
|
-
<h1
|
|
164
|
-
className={
|
|
165
|
-
styles.splittitle
|
|
166
|
-
}
|
|
167
|
-
>
|
|
168
|
-
{table.label}
|
|
169
|
-
</h1>
|
|
170
|
-
</th>
|
|
171
|
-
</tr>
|
|
172
240
|
<tr>
|
|
173
|
-
<th></th>
|
|
174
241
|
{table.columns.map((column) => (
|
|
175
242
|
<th
|
|
176
243
|
key={`${table.id}-column-${column.id}`}
|
|
177
244
|
style={
|
|
178
245
|
column.style || {}
|
|
179
246
|
}
|
|
247
|
+
className={
|
|
248
|
+
styles.tableHeader
|
|
249
|
+
}
|
|
180
250
|
>
|
|
181
|
-
{column.label
|
|
251
|
+
{column.label ===
|
|
252
|
+
'Total'
|
|
253
|
+
? 'Subtotal'
|
|
254
|
+
: column.label}
|
|
182
255
|
</th>
|
|
183
256
|
))}
|
|
184
257
|
</tr>
|
|
185
258
|
</thead>
|
|
186
259
|
<tbody>
|
|
187
|
-
{data[table.id]
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
260
|
+
{data[table.id].map(
|
|
261
|
+
(row, index) => (
|
|
262
|
+
<tr
|
|
263
|
+
key={`row-${index}`}
|
|
264
|
+
className={
|
|
265
|
+
styles.tableRow
|
|
266
|
+
}
|
|
267
|
+
>
|
|
268
|
+
{table.columns.map(
|
|
269
|
+
(column) => {
|
|
270
|
+
const cellValue =
|
|
271
|
+
get(
|
|
272
|
+
row,
|
|
273
|
+
column.id,
|
|
274
|
+
''
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
return (
|
|
196
278
|
<td
|
|
197
279
|
key={`row-${index}-column-${column.id}`}
|
|
198
280
|
style={
|
|
199
281
|
column.style ||
|
|
200
282
|
{}
|
|
201
283
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
get(
|
|
205
|
-
row,
|
|
206
|
-
column.id,
|
|
207
|
-
''
|
|
208
|
-
) // Safely access nested properties
|
|
284
|
+
className={
|
|
285
|
+
styles.tableCell
|
|
209
286
|
}
|
|
287
|
+
>
|
|
288
|
+
{column.id ===
|
|
289
|
+
'subtotal' ||
|
|
290
|
+
column.label ===
|
|
291
|
+
'Subtotal'
|
|
292
|
+
? formatCurrency(
|
|
293
|
+
parseFloat(
|
|
294
|
+
get(
|
|
295
|
+
row,
|
|
296
|
+
'rate',
|
|
297
|
+
0
|
|
298
|
+
)
|
|
299
|
+
) *
|
|
300
|
+
parseFloat(
|
|
301
|
+
get(
|
|
302
|
+
row,
|
|
303
|
+
'qty',
|
|
304
|
+
1
|
|
305
|
+
)
|
|
306
|
+
)
|
|
307
|
+
)
|
|
308
|
+
: column.type ===
|
|
309
|
+
'currency'
|
|
310
|
+
? formatCurrency(
|
|
311
|
+
cellValue
|
|
312
|
+
)
|
|
313
|
+
: cellValue}
|
|
210
314
|
</td>
|
|
211
|
-
)
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
)
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
)}
|
|
318
|
+
</tr>
|
|
319
|
+
)
|
|
320
|
+
)}
|
|
321
|
+
|
|
322
|
+
{/* Total row */}
|
|
323
|
+
<tr className={styles.subtotalRow}>
|
|
324
|
+
<td
|
|
325
|
+
colSpan={
|
|
326
|
+
table.columns.length - 1
|
|
327
|
+
}
|
|
328
|
+
className={
|
|
329
|
+
styles.subtotalLabel
|
|
330
|
+
}
|
|
331
|
+
>
|
|
332
|
+
Total
|
|
333
|
+
</td>
|
|
334
|
+
<td
|
|
335
|
+
className={
|
|
336
|
+
styles.subtotalValue
|
|
337
|
+
}
|
|
338
|
+
>
|
|
339
|
+
{formatCurrency(subtotal)}
|
|
340
|
+
</td>
|
|
341
|
+
</tr>
|
|
216
342
|
</tbody>
|
|
217
343
|
</table>
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
344
|
+
</div>
|
|
345
|
+
);
|
|
346
|
+
})}
|
|
221
347
|
</div>
|
|
222
348
|
</div>
|
|
223
|
-
|
|
349
|
+
</div>
|
|
224
350
|
);
|
|
225
351
|
}
|
|
226
352
|
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
.actionButtons {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-wrap: wrap;
|
|
4
|
+
gap: 8px;
|
|
5
|
+
padding: 0;
|
|
6
|
+
background: transparent;
|
|
7
|
+
width: 100%;
|
|
8
|
+
box-sizing: border-box;
|
|
9
|
+
justify-content: flex-end;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
.actionButton {
|
|
13
|
+
appearance: none;
|
|
14
|
+
border: 1px solid var(--primary-color);
|
|
15
|
+
border-radius: var(--br, 4px);
|
|
16
|
+
background: white;
|
|
17
|
+
color: var(--primary-color);
|
|
18
|
+
padding: 0.4rem 0.9rem;
|
|
19
|
+
font-size: 0.85rem;
|
|
20
|
+
font-weight: 500;
|
|
21
|
+
transition: all 0.2s ease;
|
|
22
|
+
display: flex;
|
|
23
|
+
align-items: center;
|
|
24
|
+
justify-content: center;
|
|
25
|
+
min-height: 32px;
|
|
26
|
+
cursor: pointer;
|
|
27
|
+
position: relative;
|
|
28
|
+
overflow: hidden;
|
|
29
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
|
30
|
+
|
|
31
|
+
&:hover {
|
|
32
|
+
background: var(--primary-color);
|
|
33
|
+
color: white;
|
|
34
|
+
transform: translateY(-1px);
|
|
35
|
+
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
&:active {
|
|
39
|
+
transform: translateY(0);
|
|
40
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
&:first-child {
|
|
44
|
+
margin-left: 0;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@media (max-width: 768px) {
|
|
49
|
+
.actionButtons {
|
|
50
|
+
flex-wrap: nowrap;
|
|
51
|
+
overflow-x: auto;
|
|
52
|
+
-webkit-overflow-scrolling: touch;
|
|
53
|
+
padding-bottom: 5px;
|
|
54
|
+
justify-content: flex-start;
|
|
55
|
+
gap: 6px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.actionButton {
|
|
59
|
+
padding: 0.3rem 0.7rem;
|
|
60
|
+
font-size: 0.75rem;
|
|
61
|
+
min-height: 30px;
|
|
62
|
+
white-space: nowrap;
|
|
63
|
+
flex: 0 0 auto;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
align-items: flex-start;
|
|
5
5
|
flex-wrap: nowrap;
|
|
6
6
|
height: auto;
|
|
7
|
-
gap:
|
|
7
|
+
gap: 0.5rem;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
.grid__row {
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
align-items: flex-start;
|
|
14
14
|
flex-wrap: nowrap;
|
|
15
15
|
height: auto;
|
|
16
|
-
gap:
|
|
16
|
+
gap: 0.5rem;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
.grid__three {
|
|
@@ -51,8 +51,8 @@
|
|
|
51
51
|
overflow: visible;
|
|
52
52
|
position: relative;
|
|
53
53
|
padding: 2px;
|
|
54
|
-
margin:
|
|
55
|
-
box-shadow: 0
|
|
54
|
+
margin: 4px 0;
|
|
55
|
+
box-shadow: 0 5px 20px rgba(var(--primary-rgb), 0.05);
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
.grid__dashfull {
|
|
@@ -76,55 +76,7 @@
|
|
|
76
76
|
gap: 0.5rem;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
flex: 1;
|
|
81
|
-
background: white;
|
|
82
|
-
border-radius: var(--br);
|
|
83
|
-
box-sizing: border-box;
|
|
84
|
-
padding: 5px;
|
|
85
|
-
margin: 8px 0;
|
|
86
|
-
height: auto;
|
|
87
|
-
box-shadow: 0 10px 50px rgba(var(--primary-rgb), 0.05);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
.grid__subnav > ul {
|
|
91
|
-
width: 100%;
|
|
92
|
-
list-style: none;
|
|
93
|
-
padding: 0;
|
|
94
|
-
margin: 0;
|
|
95
|
-
display: flex;
|
|
96
|
-
flex-wrap: wrap;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
.grid__subnav > ul li {
|
|
100
|
-
width: 100%;
|
|
101
|
-
margin-bottom: 3px;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
.grid__subnav > ul li a {
|
|
105
|
-
width: 100%;
|
|
106
|
-
padding: 0.35rem 1rem;
|
|
107
|
-
box-sizing: border-box;
|
|
108
|
-
display: block;
|
|
109
|
-
text-decoration: none;
|
|
110
|
-
background: rgba(var(--primary-rgb), 0.05);
|
|
111
|
-
color: var(--primary-color);
|
|
112
|
-
border-radius: 5px;
|
|
113
|
-
transition: background 0.25s cubic-bezier(0.25, 0.8, 0.25, 1);
|
|
114
|
-
outline: none;
|
|
115
|
-
cursor: pointer;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
.grid__subnav > ul li:hover a {
|
|
119
|
-
background: var(--primary-color);
|
|
120
|
-
color: var(--background-color);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
.grid__subnav > ul li .subactive {
|
|
124
|
-
font-weight: 700;
|
|
125
|
-
background: var(--primary-color);
|
|
126
|
-
color: var(--background-color);
|
|
127
|
-
}
|
|
79
|
+
/* Removed grid__subnav styles as we're using ActionButtons component instead */
|
|
128
80
|
|
|
129
81
|
.grid__minheight {
|
|
130
82
|
min-height: 300px;
|
|
@@ -135,15 +87,17 @@
|
|
|
135
87
|
}
|
|
136
88
|
|
|
137
89
|
.grid__subcontent {
|
|
138
|
-
flex:
|
|
90
|
+
flex: 1;
|
|
139
91
|
background: var(--tertiary-color);
|
|
140
92
|
border-radius: var(--br);
|
|
141
|
-
border: 1px solid rgba(var(--primary-rgb), 0.
|
|
93
|
+
border: 1px solid rgba(var(--primary-rgb), 0.1);
|
|
142
94
|
box-sizing: border-box;
|
|
143
|
-
padding:
|
|
144
|
-
margin:
|
|
95
|
+
padding: 0;
|
|
96
|
+
margin: 4px 0;
|
|
145
97
|
height: auto;
|
|
146
98
|
position: relative;
|
|
99
|
+
box-shadow: 0 3px 10px rgba(var(--primary-rgb), 0.05);
|
|
100
|
+
overflow: hidden;
|
|
147
101
|
}
|
|
148
102
|
|
|
149
103
|
.grid__subcontent h2 {
|
|
@@ -262,6 +216,55 @@
|
|
|
262
216
|
}
|
|
263
217
|
}
|
|
264
218
|
|
|
219
|
+
.quoteWrapper {
|
|
220
|
+
width: 100%;
|
|
221
|
+
max-width: 1200px;
|
|
222
|
+
margin: 0 auto;
|
|
223
|
+
padding: 0;
|
|
224
|
+
box-sizing: border-box;
|
|
225
|
+
background-color: white;
|
|
226
|
+
border: 1px solid #e0e0e0;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.quoteTopSection {
|
|
230
|
+
display: flex;
|
|
231
|
+
justify-content: space-between;
|
|
232
|
+
align-items: center;
|
|
233
|
+
width: 100%;
|
|
234
|
+
padding: 25px;
|
|
235
|
+
box-sizing: border-box;
|
|
236
|
+
margin-bottom: 0;
|
|
237
|
+
border-bottom: 1px solid rgba(var(--primary-rgb), 0.1);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
.quoteIdentifier {
|
|
241
|
+
flex: 1;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.quoteTitle {
|
|
245
|
+
font-size: 1.3rem;
|
|
246
|
+
font-weight: 600;
|
|
247
|
+
color: var(--primary-color);
|
|
248
|
+
margin: 0;
|
|
249
|
+
display: flex;
|
|
250
|
+
align-items: center;
|
|
251
|
+
gap: 8px;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.quoteNumber {
|
|
255
|
+
font-weight: 700;
|
|
256
|
+
color: var(--primary-color);
|
|
257
|
+
margin-left: 5px;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.actionButtonsContainer {
|
|
261
|
+
flex: 0 0 auto;
|
|
262
|
+
margin: 0;
|
|
263
|
+
padding: 0;
|
|
264
|
+
box-sizing: border-box;
|
|
265
|
+
min-width: 50%;
|
|
266
|
+
}
|
|
267
|
+
|
|
265
268
|
.titleInfo {
|
|
266
269
|
position: absolute;
|
|
267
270
|
right: 2em;
|
|
@@ -276,12 +279,14 @@
|
|
|
276
279
|
width: 100%;
|
|
277
280
|
max-width: 1450px;
|
|
278
281
|
margin: 0 auto;
|
|
279
|
-
margin-bottom:
|
|
282
|
+
margin-bottom: 15px;
|
|
280
283
|
box-sizing: border-box;
|
|
281
284
|
display: flex;
|
|
282
285
|
flex-wrap: wrap;
|
|
283
|
-
border: 1px solid rgba(var(--primary-rgb), 0.
|
|
284
|
-
border-radius:
|
|
286
|
+
border: 1px solid rgba(var(--primary-rgb), 0.2);
|
|
287
|
+
border-radius: var(--br);
|
|
288
|
+
background-color: white;
|
|
289
|
+
box-shadow: 0 2px 8px rgba(var(--primary-rgb), 0.05);
|
|
285
290
|
}
|
|
286
291
|
|
|
287
292
|
.qitem {
|
|
@@ -289,26 +294,32 @@
|
|
|
289
294
|
display: flex;
|
|
290
295
|
flex-wrap: wrap;
|
|
291
296
|
box-sizing: border-box;
|
|
292
|
-
padding:
|
|
293
|
-
border-bottom: 1px solid rgba(var(--primary-rgb), 0.
|
|
297
|
+
padding: 15px 20px;
|
|
298
|
+
border-bottom: 1px solid rgba(var(--primary-rgb), 0.15);
|
|
294
299
|
color: var(--paragraph-color);
|
|
295
300
|
|
|
301
|
+
&:last-child {
|
|
302
|
+
border-bottom: none;
|
|
303
|
+
}
|
|
304
|
+
|
|
296
305
|
&__half {
|
|
297
306
|
width: 50%;
|
|
298
307
|
box-sizing: border-box;
|
|
299
308
|
|
|
300
309
|
.qtitle {
|
|
301
310
|
display: block;
|
|
302
|
-
font-size:
|
|
311
|
+
font-size: 1.75rem;
|
|
303
312
|
text-align: right;
|
|
304
313
|
color: var(--primary-color);
|
|
314
|
+
font-weight: 600;
|
|
305
315
|
}
|
|
306
316
|
|
|
307
317
|
.qno,
|
|
308
318
|
.qdate {
|
|
309
319
|
display: block;
|
|
310
|
-
font-size:
|
|
320
|
+
font-size: 0.9rem;
|
|
311
321
|
text-align: right;
|
|
322
|
+
line-height: 1.4;
|
|
312
323
|
}
|
|
313
324
|
|
|
314
325
|
.qdate {
|
|
@@ -317,6 +328,13 @@
|
|
|
317
328
|
|
|
318
329
|
.qvisns {
|
|
319
330
|
text-align: right;
|
|
331
|
+
line-height: 1.4;
|
|
332
|
+
font-size: 0.9rem;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.qdetails {
|
|
336
|
+
line-height: 1.4;
|
|
337
|
+
font-size: 0.9rem;
|
|
320
338
|
}
|
|
321
339
|
}
|
|
322
340
|
|
|
@@ -348,113 +366,390 @@
|
|
|
348
366
|
}
|
|
349
367
|
}
|
|
350
368
|
|
|
351
|
-
.
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
369
|
+
.quoteLogoContainer {
|
|
370
|
+
flex: 0 0 30%;
|
|
371
|
+
padding-right: 20px;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.quoteLogo {
|
|
375
|
+
max-width: 180px;
|
|
376
|
+
height: auto;
|
|
377
|
+
display: block;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.quoteTitleContainer {
|
|
381
|
+
flex: 0 0 70%;
|
|
382
|
+
text-align: right;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.quoteBigNumber {
|
|
386
|
+
font-size: 1.6rem;
|
|
387
|
+
color: var(--primary-color);
|
|
388
|
+
margin: 0 0 5px 0;
|
|
389
|
+
font-weight: 600;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.quoteDate {
|
|
393
|
+
font-size: 0.9rem;
|
|
394
|
+
color: var(--paragraph-color);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
.quoteParties {
|
|
398
|
+
display: flex;
|
|
399
|
+
justify-content: space-between;
|
|
400
|
+
margin: 25px 0;
|
|
401
|
+
border-top: 1px solid rgba(var(--primary-rgb), 0.1);
|
|
402
|
+
border-bottom: 1px solid rgba(var(--primary-rgb), 0.1);
|
|
403
|
+
padding: 20px 0;
|
|
404
|
+
background-color: rgba(var(--primary-rgb), 0.02);
|
|
405
|
+
border-radius: var(--br, 4px);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.quoteParty {
|
|
409
|
+
flex: 0 0 48%;
|
|
410
|
+
padding: 0 15px;
|
|
411
|
+
|
|
412
|
+
&:first-child {
|
|
413
|
+
text-align: left;
|
|
357
414
|
}
|
|
415
|
+
|
|
416
|
+
&:last-child {
|
|
417
|
+
text-align: right;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
.partyTitle {
|
|
422
|
+
font-size: 0.95rem;
|
|
423
|
+
font-weight: 600;
|
|
424
|
+
color: var(--primary-color);
|
|
425
|
+
margin: 0 0 8px 0;
|
|
426
|
+
padding-bottom: 5px;
|
|
427
|
+
border-bottom: 1px dashed rgba(var(--primary-rgb), 0.1);
|
|
428
|
+
text-align: inherit; /* Inherit text alignment from parent */
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
.partyDetails {
|
|
432
|
+
font-size: 0.9rem;
|
|
433
|
+
line-height: 1.5;
|
|
434
|
+
color: var(--paragraph-color);
|
|
435
|
+
text-align: inherit; /* Inherit text alignment from parent */
|
|
358
436
|
}
|
|
359
437
|
|
|
360
438
|
.quotestatus {
|
|
361
439
|
width: 100%;
|
|
362
|
-
padding:
|
|
363
|
-
|
|
364
|
-
|
|
440
|
+
padding: 10px 25px;
|
|
441
|
+
display: flex;
|
|
442
|
+
justify-content: space-between;
|
|
443
|
+
align-items: center;
|
|
444
|
+
font-size: 1em;
|
|
365
445
|
box-sizing: border-box;
|
|
446
|
+
background-color: var(--primary-color, #1a3d66);
|
|
447
|
+
color: var(--tertiary-color, white);
|
|
448
|
+
border-radius: 0;
|
|
449
|
+
margin-bottom: 0;
|
|
450
|
+
box-shadow: none;
|
|
451
|
+
|
|
452
|
+
.statusLeft,
|
|
453
|
+
.statusRight {
|
|
454
|
+
display: flex;
|
|
455
|
+
align-items: center;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.statusRight {
|
|
459
|
+
font-weight: 500;
|
|
460
|
+
}
|
|
366
461
|
|
|
367
462
|
.q__accepted {
|
|
368
|
-
color:
|
|
463
|
+
color: var(--tertiary-color, white);
|
|
464
|
+
font-weight: 600;
|
|
465
|
+
background-color: #84c333;
|
|
466
|
+
padding: 4px 12px;
|
|
467
|
+
border-radius: 20px;
|
|
468
|
+
display: inline-block;
|
|
469
|
+
font-size: 0.9em;
|
|
369
470
|
}
|
|
370
471
|
|
|
371
472
|
.q__pending {
|
|
372
|
-
color:
|
|
473
|
+
color: var(--tertiary-color, white);
|
|
474
|
+
font-weight: 600;
|
|
475
|
+
background-color: #d4c141;
|
|
476
|
+
padding: 4px 12px;
|
|
477
|
+
border-radius: 20px;
|
|
478
|
+
display: inline-block;
|
|
479
|
+
font-size: 0.9em;
|
|
373
480
|
}
|
|
374
481
|
|
|
375
482
|
.q__declined {
|
|
376
|
-
color:
|
|
483
|
+
color: var(--tertiary-color, white);
|
|
484
|
+
font-weight: 600;
|
|
485
|
+
background-color: #c33333;
|
|
486
|
+
padding: 4px 12px;
|
|
487
|
+
border-radius: 20px;
|
|
488
|
+
display: inline-block;
|
|
489
|
+
font-size: 0.9em;
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
.ticketId {
|
|
493
|
+
font-size: 0.85em;
|
|
494
|
+
opacity: 0.9;
|
|
495
|
+
margin-left: 5px;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
.quoteReference {
|
|
499
|
+
font-size: 0.9em;
|
|
500
|
+
opacity: 0.9;
|
|
501
|
+
font-weight: 500;
|
|
377
502
|
}
|
|
378
503
|
}
|
|
379
504
|
|
|
380
|
-
.
|
|
381
|
-
background
|
|
382
|
-
border-
|
|
505
|
+
.quoteContent {
|
|
506
|
+
background-color: white;
|
|
507
|
+
border-radius: 0;
|
|
508
|
+
box-shadow: none;
|
|
509
|
+
padding: 25px;
|
|
510
|
+
margin-bottom: 0;
|
|
383
511
|
}
|
|
384
512
|
|
|
385
|
-
.
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
513
|
+
.quoteHeaderSection {
|
|
514
|
+
display: flex;
|
|
515
|
+
justify-content: space-between;
|
|
516
|
+
align-items: center;
|
|
517
|
+
margin-bottom: 20px;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
.quoteItems {
|
|
521
|
+
margin-top: 30px;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
.quoteTableSection {
|
|
525
|
+
margin-bottom: 25px;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
.tableTitle {
|
|
529
|
+
font-size: 1rem;
|
|
530
|
+
font-weight: 600;
|
|
531
|
+
color: var(--tertiary-color, white);
|
|
391
532
|
margin: 0;
|
|
533
|
+
padding: 10px 15px;
|
|
534
|
+
background-color: var(--primary-color, #1a3d66);
|
|
535
|
+
border-radius: 0;
|
|
536
|
+
border: none;
|
|
392
537
|
}
|
|
393
538
|
|
|
394
|
-
.
|
|
539
|
+
.quoteTable {
|
|
395
540
|
width: 100%;
|
|
541
|
+
table-layout: fixed; /* Ensures consistent column widths across tables */
|
|
396
542
|
border-collapse: collapse;
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
border-radius: 5px 5px 0 0;
|
|
543
|
+
font-size: 0.9rem;
|
|
544
|
+
border-radius: 0;
|
|
400
545
|
overflow: hidden;
|
|
401
546
|
border: none;
|
|
402
|
-
border-spacing: 0;
|
|
403
|
-
border-collapse: collapse;
|
|
404
547
|
box-sizing: border-box;
|
|
548
|
+
box-shadow: none;
|
|
549
|
+
margin-bottom: 25px;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
.tableHeader {
|
|
553
|
+
background-color: #4fbfa5;
|
|
554
|
+
color: white;
|
|
555
|
+
text-align: left;
|
|
556
|
+
font-weight: 600;
|
|
557
|
+
font-size: 0.85rem;
|
|
558
|
+
padding: 10px 15px;
|
|
559
|
+
border-bottom: none;
|
|
405
560
|
|
|
406
|
-
|
|
407
|
-
|
|
561
|
+
&:first-child {
|
|
562
|
+
border-top-left-radius: 0;
|
|
408
563
|
}
|
|
409
564
|
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
color: var(--primary-color);
|
|
413
|
-
text-align: left;
|
|
414
|
-
font-weight: 700;
|
|
415
|
-
text-transform: capitalize;
|
|
416
|
-
font-size: 1em;
|
|
565
|
+
&:last-child {
|
|
566
|
+
border-top-right-radius: 0;
|
|
417
567
|
}
|
|
418
568
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
padding: 5px;
|
|
422
|
-
}
|
|
569
|
+
&[style*='text-align: right'] {
|
|
570
|
+
text-align: right;
|
|
423
571
|
}
|
|
424
572
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
color: var(--paragraph-color);
|
|
430
|
-
border-right: 1px solid var(--table-border);
|
|
431
|
-
line-height: 1;
|
|
432
|
-
border-spacing: 0;
|
|
433
|
-
border-collapse: collapse;
|
|
573
|
+
&[style*='text-align: center'] {
|
|
574
|
+
text-align: center;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
434
577
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
578
|
+
.tableRow {
|
|
579
|
+
border-bottom: 1px solid rgba(var(--primary-rgb), 0.05);
|
|
580
|
+
transition: background-color 0.2s ease;
|
|
581
|
+
background-color: white;
|
|
582
|
+
|
|
583
|
+
&:hover {
|
|
584
|
+
background-color: rgba(var(--primary-rgb), 0.02);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
&:last-child {
|
|
588
|
+
border-bottom: none;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
&:nth-child(odd) {
|
|
592
|
+
background-color: #f9f9f9;
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
.tableCell {
|
|
597
|
+
padding: 12px 15px;
|
|
598
|
+
color: var(--paragraph-color);
|
|
599
|
+
font-size: 0.85rem;
|
|
600
|
+
line-height: 1.4;
|
|
601
|
+
vertical-align: middle;
|
|
602
|
+
|
|
603
|
+
&[style*='text-align: right'] {
|
|
604
|
+
font-weight: 600;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
&[style*='text-align: center'] {
|
|
608
|
+
text-align: center !important;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
.subtotalRow {
|
|
613
|
+
background-color: rgba(var(--primary-rgb), 0.05);
|
|
614
|
+
border-top: 1px solid rgba(var(--primary-rgb), 0.1);
|
|
438
615
|
|
|
616
|
+
&:hover {
|
|
617
|
+
background-color: rgba(var(--primary-rgb), 0.05);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
.subtotalLabel {
|
|
622
|
+
padding: 12px 15px;
|
|
623
|
+
text-align: right;
|
|
624
|
+
font-weight: 600;
|
|
625
|
+
color: var(--primary-color);
|
|
626
|
+
font-size: 0.9rem;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
.subtotalValue {
|
|
630
|
+
padding: 12px 15px;
|
|
631
|
+
text-align: right;
|
|
632
|
+
font-weight: 700;
|
|
633
|
+
color: var(--primary-color);
|
|
634
|
+
font-size: 0.9rem;
|
|
635
|
+
white-space: nowrap; /* Prevents wrapping of the value */
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/* Responsive styles */
|
|
639
|
+
@media (max-width: 768px) {
|
|
640
|
+
.quoteWrapper {
|
|
641
|
+
padding: 0 10px;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
.quoteTopSection {
|
|
645
|
+
flex-direction: column;
|
|
646
|
+
align-items: flex-start;
|
|
647
|
+
gap: 15px;
|
|
648
|
+
padding: 10px 0;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
.quoteIdentifier {
|
|
652
|
+
width: 100%;
|
|
653
|
+
margin-bottom: 0;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
.actionButtonsContainer {
|
|
657
|
+
width: 100%;
|
|
658
|
+
min-width: 100%;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
.quotestatus {
|
|
662
|
+
flex-direction: column;
|
|
663
|
+
align-items: flex-start;
|
|
664
|
+
gap: 8px;
|
|
665
|
+
font-size: 0.9em;
|
|
666
|
+
padding: 10px 15px;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
.statusLeft,
|
|
670
|
+
.statusRight {
|
|
671
|
+
width: 100%;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
.statusRight {
|
|
675
|
+
margin-top: 5px;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
.quoteContent {
|
|
679
|
+
padding: 15px;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
.quoteHeaderSection {
|
|
683
|
+
flex-direction: column;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
.quoteLogoContainer {
|
|
687
|
+
flex: 0 0 100%;
|
|
688
|
+
padding-right: 0;
|
|
689
|
+
margin-bottom: 15px;
|
|
690
|
+
text-align: center;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
.quoteLogo {
|
|
694
|
+
max-width: 150px;
|
|
695
|
+
margin: 0 auto;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
.quoteTitleContainer {
|
|
699
|
+
flex: 0 0 100%;
|
|
700
|
+
text-align: center;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
.quoteBigNumber {
|
|
704
|
+
font-size: 1.4rem;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.quoteParties {
|
|
708
|
+
flex-direction: column;
|
|
709
|
+
gap: 20px;
|
|
710
|
+
padding: 15px 0;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
.quoteParty {
|
|
714
|
+
flex: 0 0 100%;
|
|
715
|
+
padding: 0 10px;
|
|
716
|
+
|
|
717
|
+
&:first-child,
|
|
439
718
|
&:last-child {
|
|
440
|
-
|
|
719
|
+
text-align: left;
|
|
441
720
|
}
|
|
442
721
|
}
|
|
443
722
|
|
|
444
|
-
|
|
445
|
-
.
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
723
|
+
.partyTitle {
|
|
724
|
+
font-size: 0.9rem;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
.partyDetails {
|
|
728
|
+
font-size: 0.85rem;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
.tableTitle {
|
|
732
|
+
font-size: 0.9rem;
|
|
733
|
+
padding: 8px 12px;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
.quoteTable {
|
|
737
|
+
font-size: 0.8rem;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
.tableHeader {
|
|
741
|
+
padding: 8px 10px;
|
|
742
|
+
font-size: 0.8rem;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
.tableCell {
|
|
746
|
+
padding: 8px 10px;
|
|
747
|
+
font-size: 0.8rem;
|
|
453
748
|
}
|
|
454
749
|
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
750
|
+
.subtotalLabel,
|
|
751
|
+
.subtotalValue {
|
|
752
|
+
padding: 8px 10px;
|
|
753
|
+
font-size: 0.85rem;
|
|
459
754
|
}
|
|
460
755
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format a number with thousand separators (commas)
|
|
3
|
+
* @param {number|string} value - The value to format
|
|
4
|
+
* @param {number} [decimals=2] - Number of decimal places
|
|
5
|
+
* @returns {string} - Formatted number string
|
|
6
|
+
*/
|
|
7
|
+
export const formatNumber = (value, decimals = 2) => {
|
|
8
|
+
if (!value && value !== 0) return '';
|
|
9
|
+
|
|
10
|
+
// Parse the value to make sure it's a number
|
|
11
|
+
const numValue = parseFloat(String(value).replace(/[^0-9.-]+/g, ''));
|
|
12
|
+
|
|
13
|
+
if (isNaN(numValue)) return value;
|
|
14
|
+
|
|
15
|
+
// Format with specified decimal places and thousand separators
|
|
16
|
+
return numValue.toLocaleString('en-US', {
|
|
17
|
+
minimumFractionDigits: decimals,
|
|
18
|
+
maximumFractionDigits: decimals,
|
|
19
|
+
});
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Format a number as currency with dollar sign and thousand separators
|
|
24
|
+
* @param {number|string} value - The value to format
|
|
25
|
+
* @returns {string} - Formatted currency string
|
|
26
|
+
*/
|
|
27
|
+
export const formatCurrency = (value) => {
|
|
28
|
+
if (!value && value !== 0) return '';
|
|
29
|
+
|
|
30
|
+
// Parse the value to make sure it's a number
|
|
31
|
+
const numValue = parseFloat(String(value).replace(/[^0-9.-]+/g, ''));
|
|
32
|
+
|
|
33
|
+
if (isNaN(numValue)) return value;
|
|
34
|
+
|
|
35
|
+
// Format with 2 decimal places, thousand separators, and dollar sign
|
|
36
|
+
return (
|
|
37
|
+
'$' +
|
|
38
|
+
numValue.toLocaleString('en-US', {
|
|
39
|
+
minimumFractionDigits: 2,
|
|
40
|
+
maximumFractionDigits: 2,
|
|
41
|
+
})
|
|
42
|
+
);
|
|
43
|
+
};
|