@liiift-studio/sales-portal 1.2.1
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 +461 -0
- package/SETUP.md +230 -0
- package/api/getAnalytics.d.ts +38 -0
- package/api/getAnalytics.js +346 -0
- package/api/getBalanceTransactions.d.ts +29 -0
- package/api/getBalanceTransactions.js +125 -0
- package/api/getDesignerInfo.d.ts +37 -0
- package/api/getDesignerInfo.js +98 -0
- package/api/getDesigners.d.ts +28 -0
- package/api/getDesigners.js +63 -0
- package/api/getPreviousSales.d.ts +23 -0
- package/api/getPreviousSales.js +82 -0
- package/api/getSales.d.ts +29 -0
- package/api/getSales.js +50 -0
- package/api/getSalesRange.d.ts +23 -0
- package/api/getSalesRange.js +58 -0
- package/api/utils/authMiddleware.js +84 -0
- package/api/utils/dateUtils.js +69 -0
- package/api/utils/feeCalculator.js +148 -0
- package/api/utils/processors/invoiceProcessor.js +337 -0
- package/api/utils/processors/paymentProcessor.js +462 -0
- package/api/utils/salesDataProcessing.js +596 -0
- package/api/utils/salesDataProcessor.js +224 -0
- package/api/utils/stripeFetcher.js +248 -0
- package/components/DateRangeSalesTable.js +1072 -0
- package/components/DebugValues.js +48 -0
- package/components/LicenseTypeList.js +193 -0
- package/components/LoginForm.js +219 -0
- package/components/PeriodComparison.js +501 -0
- package/components/Sales.js +773 -0
- package/components/SalesChart.js +307 -0
- package/components/SalesPortalPage.js +147 -0
- package/components/SalesTable.js +677 -0
- package/components/SummaryCards.js +345 -0
- package/components/TopPerformers.js +331 -0
- package/components/TypefaceList.js +154 -0
- package/components/table-columns.js +70 -0
- package/components/table-row-cells.js +295 -0
- package/data/countryCode.json +318 -0
- package/hooks/useSalesDateQuery.d.ts +20 -0
- package/hooks/useSalesDateQuery.js +71 -0
- package/index.d.ts +172 -0
- package/index.js +33 -0
- package/package.json +87 -0
- package/styles/sales-portal.module.scss +383 -0
- package/styles/sales-portal.theme.d.ts +5 -0
- package/styles/sales-portal.theme.js +799 -0
- package/utils/currencyUtils.d.ts +20 -0
- package/utils/currencyUtils.js +79 -0
- package/utils/salesDataProcessing.d.ts +44 -0
- package/utils/salesDataProcessing.js +596 -0
- package/utils/useSalesDateQuery.js +71 -0
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
// Sales chart component displaying various sales metrics and data visualization
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { FormGroup, FormControlLabel, Checkbox } from '@mui/material';
|
|
4
|
+
import { ResponsiveChartContainer } from '@mui/x-charts/ResponsiveChartContainer';
|
|
5
|
+
import { BarPlot } from '@mui/x-charts/BarChart';
|
|
6
|
+
import { LinePlot, MarkPlot } from '@mui/x-charts/LineChart';
|
|
7
|
+
import { ChartsXAxis } from '@mui/x-charts/ChartsXAxis';
|
|
8
|
+
import { ChartsYAxis } from '@mui/x-charts/ChartsYAxis';
|
|
9
|
+
import { ChartsAxisHighlight } from '@mui/x-charts/ChartsAxisHighlight';
|
|
10
|
+
import { ChartsTooltip } from '@mui/x-charts/ChartsTooltip';
|
|
11
|
+
import styles from '../styles/sales-portal.module.scss';
|
|
12
|
+
|
|
13
|
+
const currencyFormatterCentless = new Intl.NumberFormat('en-US', {
|
|
14
|
+
style: 'currency',
|
|
15
|
+
currency: 'USD',
|
|
16
|
+
minimumFractionDigits: 0,
|
|
17
|
+
maximumFractionDigits: 0,
|
|
18
|
+
}).format;
|
|
19
|
+
|
|
20
|
+
// CurrentDate in UTC
|
|
21
|
+
const currentDate = new Date();
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Line mark styles for chart tooltips
|
|
25
|
+
* @param {string} color - Color for the line mark
|
|
26
|
+
* @returns {Object} Styles object for line marks
|
|
27
|
+
*/
|
|
28
|
+
function lineMarkStyles(color) {
|
|
29
|
+
return {
|
|
30
|
+
background: color,
|
|
31
|
+
position: 'relative',
|
|
32
|
+
'&::before': {
|
|
33
|
+
content: '""',
|
|
34
|
+
background: 'var(--white, white)',
|
|
35
|
+
position: 'absolute',
|
|
36
|
+
width: 'calc(100% - 4px)',
|
|
37
|
+
height: 'calc(100% - 4px)',
|
|
38
|
+
top: '2px',
|
|
39
|
+
left: '2px',
|
|
40
|
+
borderRadius: '50%',
|
|
41
|
+
zIndex: "2",
|
|
42
|
+
},
|
|
43
|
+
'&::after': {
|
|
44
|
+
content: '""',
|
|
45
|
+
position: 'absolute',
|
|
46
|
+
top: 'calc(50% - 1px)',
|
|
47
|
+
left: '-2px',
|
|
48
|
+
width: 'calc(100% + 4px)',
|
|
49
|
+
height: '2px',
|
|
50
|
+
background: 'inherit',
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Sales chart component for visualizing sales data
|
|
57
|
+
*/
|
|
58
|
+
export default function SalesChart({
|
|
59
|
+
sales,
|
|
60
|
+
chartState,
|
|
61
|
+
seriesData,
|
|
62
|
+
displayLosses,
|
|
63
|
+
setDisplayLosses,
|
|
64
|
+
date,
|
|
65
|
+
loading
|
|
66
|
+
}) {
|
|
67
|
+
return (
|
|
68
|
+
<div data-loading={loading}>
|
|
69
|
+
|
|
70
|
+
{/* SVG Patterns */}
|
|
71
|
+
<svg style={{ height: "0", display: "block" }}>
|
|
72
|
+
<pattern id="discountHatch" width="4" height="4" patternTransform="rotate(45 0 0)" patternUnits="userSpaceOnUse">
|
|
73
|
+
<line x1="0" y1="0" x2="0" y2="4" style={{ stroke: "black", strokeWidth: "2" }} />
|
|
74
|
+
</pattern>
|
|
75
|
+
<pattern id="discountFirstOrderHatch" width="4" height="4" patternTransform="rotate(45 0 0)" patternUnits="userSpaceOnUse">
|
|
76
|
+
<rect x="0" y="0" width="4" height="4" fill="rgba(var(--blueRGB, 0,0,255), .25)" />
|
|
77
|
+
<line x1="0" y1="0" x2="0" y2="4" style={{ stroke: "black", strokeWidth: "2" }} />
|
|
78
|
+
</pattern>
|
|
79
|
+
<pattern id="firstOrderHatch" width="4" height="4" patternTransform="rotate(45 0 0)" patternUnits="userSpaceOnUse">
|
|
80
|
+
<rect x="0" y="0" width="4" height="4" fill="rgba(var(--blueRGB, 0,0,255), .25)" />
|
|
81
|
+
</pattern>
|
|
82
|
+
</svg>
|
|
83
|
+
|
|
84
|
+
{/* Display Losses Checkbox */}
|
|
85
|
+
<div className={styles.displayLossContainer}>
|
|
86
|
+
<FormGroup>
|
|
87
|
+
<FormControlLabel
|
|
88
|
+
control={<Checkbox onChange={(e) => setDisplayLosses(e.target.checked)} size="small" />}
|
|
89
|
+
label="Show potential losses"
|
|
90
|
+
sx={{
|
|
91
|
+
mr: 0,
|
|
92
|
+
}}
|
|
93
|
+
componentsProps={{
|
|
94
|
+
typography: {
|
|
95
|
+
variant: 'body2',
|
|
96
|
+
fontSize: "12px",
|
|
97
|
+
}
|
|
98
|
+
}}
|
|
99
|
+
/>
|
|
100
|
+
</FormGroup>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
{/* Sales Chart */}
|
|
104
|
+
<ResponsiveChartContainer
|
|
105
|
+
xAxis={[{
|
|
106
|
+
data: (() => {
|
|
107
|
+
return chartState.xAxis;
|
|
108
|
+
})(),
|
|
109
|
+
valueFormatter: (v, context) => {
|
|
110
|
+
if (context?.location === "tick") return `${v}`;
|
|
111
|
+
|
|
112
|
+
// Format as "UTC: Month Day"
|
|
113
|
+
return `UTC: ${new Date(date).toLocaleString("en-US", { timeZone: 'UTC', month: "long" })} ${v}`;
|
|
114
|
+
},
|
|
115
|
+
min: chartState.xAxis[0],
|
|
116
|
+
max: (() => {
|
|
117
|
+
const lastDayOfMonth = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 0)).getUTCDate();
|
|
118
|
+
const currentUTCDate = new Date(Date.UTC(currentDate.getUTCFullYear(), currentDate.getUTCMonth(), currentDate.getUTCDate()));
|
|
119
|
+
|
|
120
|
+
if (date.getUTCMonth() === currentUTCDate.getUTCMonth() && date.getUTCFullYear() === currentUTCDate.getUTCFullYear()) {
|
|
121
|
+
return Math.min(currentUTCDate.getUTCDate(), lastDayOfMonth);
|
|
122
|
+
}
|
|
123
|
+
return date.getUTCMonth() < currentUTCDate.getUTCMonth() || date.getUTCFullYear() < currentUTCDate.getUTCFullYear()
|
|
124
|
+
? lastDayOfMonth
|
|
125
|
+
: 1;
|
|
126
|
+
})(),
|
|
127
|
+
scaleType: 'band',
|
|
128
|
+
id: 'x-axis-id',
|
|
129
|
+
tickLabelPlacement: 'middle',
|
|
130
|
+
}]}
|
|
131
|
+
yAxis={[{
|
|
132
|
+
stacked: true,
|
|
133
|
+
scaleType: 'linear',
|
|
134
|
+
valueFormatter: currencyFormatterCentless,
|
|
135
|
+
id: 'y-axis-id',
|
|
136
|
+
}]}
|
|
137
|
+
series={seriesData.length ? seriesData.map(series => ({
|
|
138
|
+
...series,
|
|
139
|
+
data: series.data.slice(0, (() => {
|
|
140
|
+
// If this is the current month, only show data up to the current day (UTC)
|
|
141
|
+
const lastDayOfMonth = new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 0)).getUTCDate();
|
|
142
|
+
const currentUTCDate = new Date(Date.UTC(currentDate.getUTCFullYear(), currentDate.getUTCMonth(), currentDate.getUTCDate()));
|
|
143
|
+
const endDate = (date.getUTCMonth() === currentUTCDate.getUTCMonth() && date.getUTCFullYear() === currentUTCDate.getUTCFullYear())
|
|
144
|
+
? Math.min(currentUTCDate.getUTCDate(), lastDayOfMonth)
|
|
145
|
+
: lastDayOfMonth;
|
|
146
|
+
return endDate;
|
|
147
|
+
})())
|
|
148
|
+
})) : []}
|
|
149
|
+
height={!!sales.length ? 300 : 75}
|
|
150
|
+
className={'chart'}
|
|
151
|
+
skipAnimation
|
|
152
|
+
disableAxisListener={false}
|
|
153
|
+
>
|
|
154
|
+
<BarPlot
|
|
155
|
+
borderRadius={4}
|
|
156
|
+
sx={{
|
|
157
|
+
'& .MuiBarElement-root': {
|
|
158
|
+
transition: 'all 0.2s ease-in-out',
|
|
159
|
+
}
|
|
160
|
+
}}
|
|
161
|
+
/>
|
|
162
|
+
<LinePlot
|
|
163
|
+
sx={{
|
|
164
|
+
'& .MuiLineElement-root': {
|
|
165
|
+
transition: 'all 0.2s ease-in-out',
|
|
166
|
+
}
|
|
167
|
+
}}
|
|
168
|
+
/>
|
|
169
|
+
<ChartsYAxis axisId="y-axis-id" />
|
|
170
|
+
<ChartsXAxis axisId="x-axis-id" />
|
|
171
|
+
<ChartsAxisHighlight x='line' />
|
|
172
|
+
<ChartsTooltip
|
|
173
|
+
slotProps={{
|
|
174
|
+
popper: {
|
|
175
|
+
sx: {
|
|
176
|
+
// The wrap
|
|
177
|
+
["& .MuiChartsTooltip-root"]: {
|
|
178
|
+
boxShadow: "0 0 10px rgba(var(--blackRGB, 0,0,0), 0.1)",
|
|
179
|
+
padding: "10px",
|
|
180
|
+
},
|
|
181
|
+
["& .MuiChartsTooltip-paper::after"]: {
|
|
182
|
+
content: '"non-applicable fields are hidden"',
|
|
183
|
+
fontSize: "10px",
|
|
184
|
+
maxWidth: "100%",
|
|
185
|
+
textAlign: "center",
|
|
186
|
+
background: "rgba(var(--blackRGB, 0,0,0), 0.1)",
|
|
187
|
+
display: "block",
|
|
188
|
+
color: "rgba(var(--blackRGB, 0,0,0), 0.5)",
|
|
189
|
+
padding: "5px",
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
// The title
|
|
193
|
+
["& .MuiChartsTooltip-paper thead"]: {
|
|
194
|
+
background: "var(--black, black)",
|
|
195
|
+
},
|
|
196
|
+
["& .MuiChartsTooltip-paper thead *"]: {
|
|
197
|
+
color: "var(--white, white)",
|
|
198
|
+
textAlign: "center",
|
|
199
|
+
fontWeight: "900",
|
|
200
|
+
fontVariationSettings: '"wght" 900, "wdth" 500',
|
|
201
|
+
fontSize: "14px",
|
|
202
|
+
letterSpacing: "0.01em",
|
|
203
|
+
textTransform: "uppercase",
|
|
204
|
+
},
|
|
205
|
+
// The body
|
|
206
|
+
["& .MuiChartsTooltip-paper tbody tr:nth-of-type(odd)"]: {
|
|
207
|
+
background: "rgba(var(--blackRGB, 0,0,0), 0.1)",
|
|
208
|
+
padding: "10px",
|
|
209
|
+
},
|
|
210
|
+
["& .MuiChartsTooltip-paper tbody tr * "]: {
|
|
211
|
+
fontSize: "14px",
|
|
212
|
+
letterSpacing: "0.01em",
|
|
213
|
+
textTransform: "uppercase",
|
|
214
|
+
lineHeight: "1",
|
|
215
|
+
padding: "5px",
|
|
216
|
+
},
|
|
217
|
+
// The mark
|
|
218
|
+
["& .MuiChartsTooltip-mark"]: {
|
|
219
|
+
border: "none",
|
|
220
|
+
outline: "none",
|
|
221
|
+
boxShadow: "none",
|
|
222
|
+
marginLeft: "5px",
|
|
223
|
+
mixBlendMode: "multiply",
|
|
224
|
+
},
|
|
225
|
+
// Mark styling for discounts
|
|
226
|
+
["& .MuiChartsTooltip-row:first-of-type .MuiChartsTooltip-mark"]: {
|
|
227
|
+
background:
|
|
228
|
+
(
|
|
229
|
+
(chartState.discountData?.length > 0 && chartState.discountData.some(value => value !== 0)) &&
|
|
230
|
+
(chartState.discountFirstOrderData?.length > 0 && chartState.discountFirstOrderData.some(value => value !== 0))
|
|
231
|
+
) ?
|
|
232
|
+
'repeating-linear-gradient( -45deg, transparent, transparent 2px, black 0px, black 3px, transparent 0px, transparent 4px), rgba(0,0,0,0.05)'
|
|
233
|
+
: '',
|
|
234
|
+
},
|
|
235
|
+
["& .MuiChartsTooltip-row:nth-of-type(2) .MuiChartsTooltip-mark"]: {
|
|
236
|
+
background:
|
|
237
|
+
(
|
|
238
|
+
(chartState.discountData?.length > 0 && chartState.discountData.some(value => value !== 0)) &&
|
|
239
|
+
(chartState.discountFirstOrderData?.length > 0 && chartState.discountFirstOrderData.some(value => value !== 0))
|
|
240
|
+
) ?
|
|
241
|
+
'repeating-linear-gradient( -45deg, transparent, transparent 2px, black 0px, black 3px, transparent 0px, transparent 4px), rgba(var(--blueRGB, 0,0,255), .25)'
|
|
242
|
+
: '',
|
|
243
|
+
},
|
|
244
|
+
["& .MuiChartsTooltip-row:first-of-type .MuiChartsTooltip-mark"]: {
|
|
245
|
+
background:
|
|
246
|
+
(
|
|
247
|
+
(chartState.discountData?.length > 0 && chartState.discountData.some(value => value !== 0)) &&
|
|
248
|
+
!(!!chartState.discountFirstOrderData?.length > 0 && !!chartState.discountFirstOrderData.some(value => value !== 0))
|
|
249
|
+
) ?
|
|
250
|
+
'repeating-linear-gradient( -45deg, transparent, transparent 2px, black 0px, black 3px, transparent 0px, transparent 4px), rgba(0,0,0,0.05)'
|
|
251
|
+
: (
|
|
252
|
+
!(chartState.discountData?.length > 0 && chartState.discountData.some(value => value !== 0)) &&
|
|
253
|
+
(!!chartState.discountFirstOrderData?.length > 0 && !!chartState.discountFirstOrderData.some(value => value !== 0))
|
|
254
|
+
) ?
|
|
255
|
+
'repeating-linear-gradient( -45deg, transparent, transparent 2px, black 0px, black 3px, transparent 0px, transparent 4px), rgba(var(--blueRGB, 0,0,255), .25)'
|
|
256
|
+
: '',
|
|
257
|
+
},
|
|
258
|
+
// Mark styling for lines
|
|
259
|
+
[`& .MuiChartsTooltip-row:nth-last-of-type(${
|
|
260
|
+
displayLosses && !!(chartState.taxData?.length > 0 && chartState.taxData.some(value => value !== 0)) && !!(chartState.shippingData?.length > 0 && chartState.shippingData.some(value => value !== 0)) ?
|
|
261
|
+
5
|
|
262
|
+
:
|
|
263
|
+
(displayLosses || !!(chartState.taxData?.length > 0 && chartState.taxData.some(value => value !== 0))) && !!(chartState.shippingData?.length > 0 && chartState.shippingData.some(value => value !== 0)) ?
|
|
264
|
+
4
|
|
265
|
+
:
|
|
266
|
+
!!(chartState.shippingData?.length > 0 && chartState.shippingData.some(value => value !== 0)) ?
|
|
267
|
+
3
|
|
268
|
+
:
|
|
269
|
+
-1
|
|
270
|
+
}) .MuiChartsTooltip-mark`]: {
|
|
271
|
+
...lineMarkStyles('var(--orange, orange)')
|
|
272
|
+
},
|
|
273
|
+
[`& .MuiChartsTooltip-row:nth-last-of-type(${
|
|
274
|
+
displayLosses && !!(chartState.taxData?.length > 0 && chartState.taxData.some(value => value !== 0)) ?
|
|
275
|
+
4
|
|
276
|
+
:
|
|
277
|
+
!!(chartState.taxData?.length > 0 && chartState.taxData.some(value => value !== 0)) ?
|
|
278
|
+
3
|
|
279
|
+
:
|
|
280
|
+
-1
|
|
281
|
+
}) .MuiChartsTooltip-mark`]: {
|
|
282
|
+
...lineMarkStyles('var(--red, red)')
|
|
283
|
+
},
|
|
284
|
+
[`& .MuiChartsTooltip-row:nth-last-of-type(${
|
|
285
|
+
displayLosses ? 3 : 2
|
|
286
|
+
}) .MuiChartsTooltip-mark`]: {
|
|
287
|
+
...lineMarkStyles('var(--green, green)')
|
|
288
|
+
},
|
|
289
|
+
[`& .MuiChartsTooltip-row:nth-last-of-type(${
|
|
290
|
+
displayLosses ? 2 : 1
|
|
291
|
+
}) .MuiChartsTooltip-mark`]: {
|
|
292
|
+
...lineMarkStyles('var(--blue, blue)')
|
|
293
|
+
},
|
|
294
|
+
[`& .MuiChartsTooltip-row:nth-last-of-type(${
|
|
295
|
+
displayLosses ? 1 : -1
|
|
296
|
+
}) .MuiChartsTooltip-mark`]: {
|
|
297
|
+
...lineMarkStyles('var(--black, black)')
|
|
298
|
+
},
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
}}
|
|
302
|
+
/>
|
|
303
|
+
<MarkPlot />
|
|
304
|
+
</ResponsiveChartContainer>
|
|
305
|
+
</div>
|
|
306
|
+
);
|
|
307
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// Complete sales portal page component with login and dashboard views
|
|
2
|
+
import React, { useState } from 'react';
|
|
3
|
+
import { Grid, Typography } from '@mui/material';
|
|
4
|
+
import { ThemeProvider } from '@mui/system';
|
|
5
|
+
import { salesTheme } from '../styles/sales-portal.theme.js';
|
|
6
|
+
import Sales from './Sales.js';
|
|
7
|
+
import LoginForm from './LoginForm.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* SalesPortalPage - Complete sales portal page with authentication and dashboard
|
|
11
|
+
*
|
|
12
|
+
* This component provides the full sales portal experience:
|
|
13
|
+
* - Login form for designer authentication
|
|
14
|
+
* - Post-login dashboard with admin and designer views
|
|
15
|
+
* - Automatic theme wrapping
|
|
16
|
+
*
|
|
17
|
+
* @param {Object} props Component props
|
|
18
|
+
* @param {Function} props.renderLoader Optional render prop for custom loader (receives { fill, position, height })
|
|
19
|
+
* @param {Object} props.texts Optional text customization for login form
|
|
20
|
+
* @param {boolean} props.includeTheme Whether to wrap with salesTheme (default: true)
|
|
21
|
+
* @param {Object} props.pageStyles Optional custom styles for the page container
|
|
22
|
+
* @param {Object} props.dashboardStyles Optional custom styles for the dashboard container
|
|
23
|
+
*/
|
|
24
|
+
export default function SalesPortalPage({
|
|
25
|
+
renderLoader,
|
|
26
|
+
texts = {},
|
|
27
|
+
includeTheme = true,
|
|
28
|
+
pageStyles = {},
|
|
29
|
+
dashboardStyles = {}
|
|
30
|
+
}) {
|
|
31
|
+
// Authentication state
|
|
32
|
+
const [designers, setDesigners] = useState(null);
|
|
33
|
+
const [admin, setAdmin] = useState(false);
|
|
34
|
+
const [credentials, setCredentials] = useState({ user: '', password: '' });
|
|
35
|
+
|
|
36
|
+
// Date state for syncing across Sales components
|
|
37
|
+
const [month, setMonth] = useState(new Date().getUTCMonth());
|
|
38
|
+
const [year, setYear] = useState(new Date().getUTCFullYear());
|
|
39
|
+
|
|
40
|
+
const handleLoginSuccess = ({ designers, admin, user, password }) => {
|
|
41
|
+
setDesigners(designers);
|
|
42
|
+
setAdmin(admin);
|
|
43
|
+
setCredentials({ user, password });
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const updateDate = (newDate) => {
|
|
47
|
+
setMonth(new Date(newDate).getUTCMonth());
|
|
48
|
+
setYear(new Date(newDate).getUTCFullYear());
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// Default page title text
|
|
52
|
+
const {
|
|
53
|
+
dashboardTitle = 'Monthly Sales',
|
|
54
|
+
dashboardSubtitle = 'by designer'
|
|
55
|
+
} = texts;
|
|
56
|
+
|
|
57
|
+
const content = (
|
|
58
|
+
<>
|
|
59
|
+
{designers ? (
|
|
60
|
+
<>
|
|
61
|
+
{/* Admin View - Shows foundry-wide data */}
|
|
62
|
+
{admin && (
|
|
63
|
+
<Grid container columnSpacing={10} sx={{
|
|
64
|
+
position: 'relative',
|
|
65
|
+
display: 'flex',
|
|
66
|
+
alignContent: 'flex-start',
|
|
67
|
+
background: 'rgba(0,0,0,.06)',
|
|
68
|
+
...dashboardStyles
|
|
69
|
+
}}>
|
|
70
|
+
<Grid item xs={12}>
|
|
71
|
+
<Sales
|
|
72
|
+
key={'sales-admin'}
|
|
73
|
+
month={month}
|
|
74
|
+
year={year}
|
|
75
|
+
updateDate={updateDate}
|
|
76
|
+
designer={{
|
|
77
|
+
admin: true,
|
|
78
|
+
firstName: '',
|
|
79
|
+
lastName: 'The Foundry',
|
|
80
|
+
user: credentials.user,
|
|
81
|
+
password: credentials.password
|
|
82
|
+
}}
|
|
83
|
+
categories={true}
|
|
84
|
+
admin={true}
|
|
85
|
+
/>
|
|
86
|
+
</Grid>
|
|
87
|
+
</Grid>
|
|
88
|
+
)}
|
|
89
|
+
|
|
90
|
+
{/* Designer Sales View */}
|
|
91
|
+
<Grid container columnSpacing={10} sx={{
|
|
92
|
+
pb: 20,
|
|
93
|
+
position: 'relative',
|
|
94
|
+
display: 'flex',
|
|
95
|
+
alignContent: 'flex-start',
|
|
96
|
+
minHeight: '80vh',
|
|
97
|
+
...pageStyles
|
|
98
|
+
}}>
|
|
99
|
+
<Grid
|
|
100
|
+
id='titleContainer'
|
|
101
|
+
item
|
|
102
|
+
xs={12}
|
|
103
|
+
sx={{
|
|
104
|
+
pt: 10,
|
|
105
|
+
mx: { xs: 'var(--marginXMobile)', md: 'var(--marginX)' },
|
|
106
|
+
}}
|
|
107
|
+
>
|
|
108
|
+
<Typography variant='h1'>{dashboardTitle}</Typography>
|
|
109
|
+
{admin && <Typography variant='h5'>{dashboardSubtitle}</Typography>}
|
|
110
|
+
</Grid>
|
|
111
|
+
|
|
112
|
+
{designers.map((designer, i) => (
|
|
113
|
+
<Sales
|
|
114
|
+
key={`sales-${i}`}
|
|
115
|
+
designer={{
|
|
116
|
+
...designer,
|
|
117
|
+
user: designer.user || credentials.user,
|
|
118
|
+
password: designer.password || credentials.password
|
|
119
|
+
}}
|
|
120
|
+
month={month}
|
|
121
|
+
year={year}
|
|
122
|
+
updateDate={updateDate}
|
|
123
|
+
/>
|
|
124
|
+
))}
|
|
125
|
+
</Grid>
|
|
126
|
+
</>
|
|
127
|
+
) : (
|
|
128
|
+
<LoginForm
|
|
129
|
+
onLoginSuccess={handleLoginSuccess}
|
|
130
|
+
renderLoader={renderLoader}
|
|
131
|
+
texts={texts}
|
|
132
|
+
/>
|
|
133
|
+
)}
|
|
134
|
+
</>
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
// Optionally wrap with theme provider
|
|
138
|
+
if (includeTheme) {
|
|
139
|
+
return (
|
|
140
|
+
<ThemeProvider theme={salesTheme}>
|
|
141
|
+
{content}
|
|
142
|
+
</ThemeProvider>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return content;
|
|
147
|
+
}
|