@liiift-studio/sales-portal 3.0.0 → 3.1.0
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 +1 -1
- package/SETUP.md +1 -1
- package/api/utils/processors/invoiceProcessor.js +2 -2
- package/components/DateRangeSalesTable.js +1 -1
- package/components/Sales.js +80 -46
- package/components/SalesPortalPage.js +1 -1
- package/components/SalesTable.js +1 -1
- package/package.json +1 -1
- package/styles/sales-portal.module.scss +1 -1
- package/styles/sales-portal.theme.js +1 -1
package/README.md
CHANGED
package/SETUP.md
CHANGED
|
@@ -39,7 +39,7 @@ export default function SalesPortal() {
|
|
|
39
39
|
title: 'Sales Portal',
|
|
40
40
|
description: 'Track your typeface sales performance and revenue.',
|
|
41
41
|
subtitle: 'All sales are reviewed internally before payouts.',
|
|
42
|
-
dashboardTitle: '
|
|
42
|
+
dashboardTitle: 'Sales',
|
|
43
43
|
dashboardSubtitle: 'by designer'
|
|
44
44
|
}}
|
|
45
45
|
/>
|
|
@@ -17,8 +17,8 @@ import { isTestSale } from '../clients';
|
|
|
17
17
|
function findMatches({ invoice, line = {}, sanitySales = [] }) {
|
|
18
18
|
// Find matching order
|
|
19
19
|
const associatedOrder =
|
|
20
|
-
(invoice?.id && sanitySales.find(order => order
|
|
21
|
-
(invoice?.payment_intent && sanitySales.find(order => order
|
|
20
|
+
(invoice?.id && sanitySales.find(order => order?.orderStatus?.invoiceId === invoice.id)) ||
|
|
21
|
+
(invoice?.payment_intent && sanitySales.find(order => order?.orderStatus?.paymentIntentId === invoice.payment_intent)) ||
|
|
22
22
|
(invoice?.customer?.email && sanitySales.find(order => {
|
|
23
23
|
const orderDate = new Date(order._createdAt);
|
|
24
24
|
const invoiceDate = new Date(invoice.created * 1000);
|
|
@@ -514,7 +514,7 @@ export function DateRangeSalesTable({ designer, admin, loading, updateLoadingSta
|
|
|
514
514
|
? '2px solid var(--green, green)'
|
|
515
515
|
: '2px solid var(--red, red)',
|
|
516
516
|
color: reconciliationData.isReconciled
|
|
517
|
-
? 'var(--
|
|
517
|
+
? 'var(--black, #1a1a1a)'
|
|
518
518
|
: 'var(--red, red)',
|
|
519
519
|
backgroundColor: 'rgba(255, 255, 255, 0.9)',
|
|
520
520
|
filter: 'invert(0) !important',
|
package/components/Sales.js
CHANGED
|
@@ -203,6 +203,11 @@ export default function Sales(props) {
|
|
|
203
203
|
},
|
|
204
204
|
'Sales data'
|
|
205
205
|
);
|
|
206
|
+
|
|
207
|
+
if (!response.ok) {
|
|
208
|
+
throw new Error(`HTTP ${response.status}`);
|
|
209
|
+
}
|
|
210
|
+
|
|
206
211
|
const data = await response.json();
|
|
207
212
|
|
|
208
213
|
if (data.success) {
|
|
@@ -257,6 +262,10 @@ export default function Sales(props) {
|
|
|
257
262
|
'Previous sales data'
|
|
258
263
|
);
|
|
259
264
|
|
|
265
|
+
if (!response.ok) {
|
|
266
|
+
throw new Error(`HTTP ${response.status}`);
|
|
267
|
+
}
|
|
268
|
+
|
|
260
269
|
const data = await response.json();
|
|
261
270
|
|
|
262
271
|
if (data.success) {
|
|
@@ -314,8 +323,27 @@ export default function Sales(props) {
|
|
|
314
323
|
const processedLicenseTypeData = processLicenseTypeData(sales);
|
|
315
324
|
setLicenseTypeData(processedLicenseTypeData);
|
|
316
325
|
|
|
317
|
-
// Set total sales
|
|
318
|
-
const
|
|
326
|
+
// Set total sales from unique invoice amounts (accounts for discounts correctly)
|
|
327
|
+
const seenInvoices = new Set();
|
|
328
|
+
let totalRevenue = 0;
|
|
329
|
+
sales.forEach(s => {
|
|
330
|
+
if (s.shippingProvision) return;
|
|
331
|
+
const sid = s.id;
|
|
332
|
+
if (sid && !seenInvoices.has(sid)) {
|
|
333
|
+
seenInvoices.add(sid);
|
|
334
|
+
totalRevenue += (s.invoiceTotal || s.total || 0) / 100;
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
// Subtract refunds
|
|
338
|
+
const seenRefunds = new Set();
|
|
339
|
+
sales.forEach(s => {
|
|
340
|
+
s.refunds?.forEach(r => {
|
|
341
|
+
if (r.id && !seenRefunds.has(r.id)) {
|
|
342
|
+
seenRefunds.add(r.id);
|
|
343
|
+
totalRevenue -= (r.total || 0) / 100;
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
});
|
|
319
347
|
setTotal(totalRevenue);
|
|
320
348
|
|
|
321
349
|
// Calculate revenue change percentage compared to previous period
|
|
@@ -567,10 +595,14 @@ export default function Sales(props) {
|
|
|
567
595
|
data-disabled={loading}
|
|
568
596
|
>
|
|
569
597
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
|
570
|
-
<IconButton
|
|
598
|
+
<IconButton
|
|
571
599
|
onClick={() => {
|
|
572
600
|
const newDate = new Date(date);
|
|
573
|
-
|
|
601
|
+
if (viewMode === 'year') {
|
|
602
|
+
newDate.setUTCFullYear(date.getUTCFullYear() - 1);
|
|
603
|
+
} else {
|
|
604
|
+
newDate.setUTCMonth(date.getUTCMonth() - 1);
|
|
605
|
+
}
|
|
574
606
|
setDate(newDate);
|
|
575
607
|
}}
|
|
576
608
|
size="small"
|
|
@@ -579,19 +611,23 @@ export default function Sales(props) {
|
|
|
579
611
|
<ChevronLeftIcon />
|
|
580
612
|
</IconButton>
|
|
581
613
|
<DatePicker
|
|
582
|
-
label='Month/Year (UTC)'
|
|
583
|
-
views={['month', 'year']}
|
|
584
|
-
format=
|
|
614
|
+
label={viewMode === 'year' ? 'Year (UTC)' : 'Month/Year (UTC)'}
|
|
615
|
+
views={viewMode === 'year' ? ['year'] : ['month', 'year']}
|
|
616
|
+
format={viewMode === 'year' ? 'YYYY' : 'MMM YYYY'}
|
|
585
617
|
formatDensity="dense"
|
|
586
618
|
slotProps={{ textField: { variant: "filled" } }}
|
|
587
619
|
sx={{ "& *": { borderRadius: "4px" } }}
|
|
588
620
|
value={dayjs.utc(date)}
|
|
589
621
|
onChange={(newValue) => setDate(newValue.toDate())}
|
|
590
622
|
/>
|
|
591
|
-
<IconButton
|
|
623
|
+
<IconButton
|
|
592
624
|
onClick={() => {
|
|
593
625
|
const newDate = new Date(date);
|
|
594
|
-
|
|
626
|
+
if (viewMode === 'year') {
|
|
627
|
+
newDate.setUTCFullYear(date.getUTCFullYear() + 1);
|
|
628
|
+
} else {
|
|
629
|
+
newDate.setUTCMonth(date.getUTCMonth() + 1);
|
|
630
|
+
}
|
|
595
631
|
setDate(newDate);
|
|
596
632
|
}}
|
|
597
633
|
size="small"
|
|
@@ -783,25 +819,9 @@ export default function Sales(props) {
|
|
|
783
819
|
<Box sx={{ display: 'flex', flexWrap: 'wrap', width: '100%' }}>
|
|
784
820
|
{HeaderSection}
|
|
785
821
|
|
|
786
|
-
{/*
|
|
787
|
-
{
|
|
788
|
-
<Box sx={{ width: '100%', px: { xs: 2, md: 0 } }}>
|
|
789
|
-
<YearOverview
|
|
790
|
-
designer={designer}
|
|
791
|
-
year={date.getUTCFullYear()}
|
|
792
|
-
onMonthClick={(monthIndex) => {
|
|
793
|
-
const newDate = new Date(Date.UTC(date.getUTCFullYear(), monthIndex, 1));
|
|
794
|
-
setDate(newDate);
|
|
795
|
-
setViewMode('month');
|
|
796
|
-
}}
|
|
797
|
-
/>
|
|
798
|
-
</Box>
|
|
799
|
-
)}
|
|
800
|
-
|
|
801
|
-
{/* Monthly Sales Data Display */}
|
|
802
|
-
{viewMode === 'month' && !!sales.length && (
|
|
822
|
+
{/* Sales Data Display */}
|
|
823
|
+
{!!sales.length && (
|
|
803
824
|
<>
|
|
804
|
-
|
|
805
825
|
<Box
|
|
806
826
|
data-disabled={loading}
|
|
807
827
|
className={`sales-data-section ${styles.salesSection}`}
|
|
@@ -813,18 +833,32 @@ export default function Sales(props) {
|
|
|
813
833
|
}}
|
|
814
834
|
>
|
|
815
835
|
|
|
816
|
-
{/* Chart Section */}
|
|
817
|
-
|
|
818
|
-
<
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
836
|
+
{/* Chart Section — Year or Month */}
|
|
837
|
+
{viewMode === 'year' && date ? (
|
|
838
|
+
<Box className="year-overview-wrapper">
|
|
839
|
+
<YearOverview
|
|
840
|
+
designer={designer}
|
|
841
|
+
year={date.getUTCFullYear()}
|
|
842
|
+
onMonthClick={(monthIndex) => {
|
|
843
|
+
const newDate = new Date(Date.UTC(date.getUTCFullYear(), monthIndex, 1));
|
|
844
|
+
setDate(newDate);
|
|
845
|
+
setViewMode('month');
|
|
846
|
+
}}
|
|
847
|
+
/>
|
|
848
|
+
</Box>
|
|
849
|
+
) : (
|
|
850
|
+
<Box className="sales-chart-wrapper">
|
|
851
|
+
<SalesChart
|
|
852
|
+
sales={sales}
|
|
853
|
+
chartState={chartState}
|
|
854
|
+
seriesData={seriesData}
|
|
855
|
+
displayLosses={displayLosses}
|
|
856
|
+
setDisplayLosses={setDisplayLosses}
|
|
857
|
+
date={date}
|
|
858
|
+
loading={loading}
|
|
859
|
+
/>
|
|
860
|
+
</Box>
|
|
861
|
+
)}
|
|
828
862
|
|
|
829
863
|
{/* Summary Dashboard */}
|
|
830
864
|
<Box className="summary-cards-wrapper">
|
|
@@ -876,7 +910,7 @@ export default function Sales(props) {
|
|
|
876
910
|
{/* Sales Table Section */}
|
|
877
911
|
{designer && (
|
|
878
912
|
<Box className="sales-table-wrapper">
|
|
879
|
-
<SalesTable
|
|
913
|
+
<SalesTable
|
|
880
914
|
sales={sales}
|
|
881
915
|
designer={designer}
|
|
882
916
|
admin={admin}
|
|
@@ -889,12 +923,12 @@ export default function Sales(props) {
|
|
|
889
923
|
</Box>
|
|
890
924
|
|
|
891
925
|
{/* Date Range Sales Table Section */}
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
926
|
+
<DateRangeSalesTable
|
|
927
|
+
designer={designer}
|
|
928
|
+
admin={admin}
|
|
929
|
+
loading={loadingStates.dateRangeSalesData}
|
|
930
|
+
updateLoadingState={updateLoadingState}
|
|
931
|
+
/>
|
|
898
932
|
</>
|
|
899
933
|
)}
|
|
900
934
|
|
package/components/SalesTable.js
CHANGED
|
@@ -173,7 +173,7 @@ export function SalesTable({ sales = [], designer = {}, admin = false, loading =
|
|
|
173
173
|
? '2px solid var(--green, green)'
|
|
174
174
|
: '2px solid var(--red, red)',
|
|
175
175
|
color: reconciliationData.isReconciled
|
|
176
|
-
? 'var(--
|
|
176
|
+
? 'var(--black, #1a1a1a)'
|
|
177
177
|
: 'var(--red, red)',
|
|
178
178
|
}}>
|
|
179
179
|
{reconciliationData.isLoading ? (
|
package/package.json
CHANGED
|
@@ -27,7 +27,7 @@ let size = createTheme({
|
|
|
27
27
|
let typography = createTheme({
|
|
28
28
|
|
|
29
29
|
typography: {
|
|
30
|
-
fontFamily: '
|
|
30
|
+
fontFamily: 'inherit, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif',
|
|
31
31
|
h1: {
|
|
32
32
|
maxWidth: '95%',
|
|
33
33
|
fontStyle: 'normal',
|