@liiift-studio/sales-portal 1.2.3 → 1.3.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/api/getBalanceTransactions.js +3 -1
- package/api/getDesignerInfo.js +3 -1
- package/api/utils/stripeFetcher.js +3 -1
- package/components/DateRangeSalesTable.js +100 -108
- package/components/LicenseTypeList.js +6 -8
- package/components/LoginForm.js +165 -133
- package/components/PeriodComparison.js +8 -9
- package/components/Sales.js +23 -26
- package/components/SalesPortalPage.js +81 -78
- package/components/SalesTable.js +88 -99
- package/components/SummaryCards.js +13 -13
- package/components/TopPerformers.js +13 -17
- package/components/TypefaceList.js +6 -8
- package/package.json +1 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// API endpoint to fetch Stripe balance transactions for reconciliation
|
|
2
|
-
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY
|
|
2
|
+
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY, {
|
|
3
|
+
maxNetworkRetries: 3,
|
|
4
|
+
});
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* Fetches Stripe balance transactions for a specific month
|
package/api/getDesignerInfo.js
CHANGED
|
@@ -5,7 +5,9 @@ export const config = { maxDuration: 300 };
|
|
|
5
5
|
|
|
6
6
|
// Import required dependencies
|
|
7
7
|
const { createClient } = require('@sanity/client');
|
|
8
|
-
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY
|
|
8
|
+
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY, {
|
|
9
|
+
maxNetworkRetries: 3,
|
|
10
|
+
});
|
|
9
11
|
|
|
10
12
|
/**
|
|
11
13
|
* Sanity client configuration for CMS interactions
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
* Utility functions for fetching data from Stripe API
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY
|
|
5
|
+
const stripe = require('stripe')(process.env.STRIPE_SECRET_KEY, {
|
|
6
|
+
maxNetworkRetries: 3,
|
|
7
|
+
});
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* Fetches dispute details including all balance transactions
|
|
@@ -2,15 +2,14 @@
|
|
|
2
2
|
import React, { useState, useEffect, useMemo } from 'react';
|
|
3
3
|
import { useRouter } from 'next/router';
|
|
4
4
|
var slugify = require('slugify');
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
Table,
|
|
5
|
+
import {
|
|
6
|
+
Button,
|
|
7
|
+
TableRow,
|
|
8
|
+
TableHead,
|
|
9
|
+
TableContainer,
|
|
10
|
+
TableCell,
|
|
11
|
+
TableBody,
|
|
12
|
+
Table,
|
|
14
13
|
Typography,
|
|
15
14
|
Menu,
|
|
16
15
|
MenuItem,
|
|
@@ -53,13 +52,11 @@ export function DateRangeSalesTable({ designer, admin, loading, updateLoadingSta
|
|
|
53
52
|
// Early return if no designer data is available - MOVED TO TOP before any hooks
|
|
54
53
|
if (!designer?.user || !designer?.password) {
|
|
55
54
|
return (
|
|
56
|
-
<
|
|
57
|
-
<
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
</Grid>
|
|
62
|
-
</Grid>
|
|
55
|
+
<Box sx={{ mt: 16, width: '100%' }}>
|
|
56
|
+
<Typography variant="h6" sx={{ color: 'var(--red, red)' }}>
|
|
57
|
+
Error: Designer credentials not available
|
|
58
|
+
</Typography>
|
|
59
|
+
</Box>
|
|
63
60
|
);
|
|
64
61
|
}
|
|
65
62
|
|
|
@@ -568,28 +565,30 @@ export function DateRangeSalesTable({ designer, admin, loading, updateLoadingSta
|
|
|
568
565
|
};
|
|
569
566
|
|
|
570
567
|
return (
|
|
571
|
-
<
|
|
572
|
-
|
|
573
|
-
data-
|
|
574
|
-
data-loading={loading}
|
|
568
|
+
<Box
|
|
569
|
+
data-disabled={loading}
|
|
570
|
+
data-loading={loading}
|
|
575
571
|
className={`date-range-sales-table-wrapper exportSection ${styles.exportSection} ${styles.salesSection}`}
|
|
576
|
-
sx={{
|
|
577
|
-
|
|
578
|
-
|
|
572
|
+
sx={{
|
|
573
|
+
display: 'flex',
|
|
574
|
+
flexWrap: 'wrap',
|
|
575
|
+
width: '100%',
|
|
576
|
+
mt: 32,
|
|
577
|
+
pt: 16,
|
|
579
578
|
pb: 8,
|
|
580
579
|
mb: '0!important',
|
|
581
580
|
background: "rgba(0,0,0,.85)",
|
|
582
581
|
"& > *": {filter: "invert(1)"}
|
|
583
582
|
}}
|
|
584
583
|
>
|
|
585
|
-
<
|
|
584
|
+
<Box id='titleContainer' sx={{ width: { xs: '100%', sm: '50%', md: '66.67%' } }}>
|
|
586
585
|
<Typography variant='h3'>
|
|
587
586
|
Export {designer?.firstName ? `${designer.firstName}'s`: designer?.name ? `${designer.name}'s` : ''} Sales
|
|
588
587
|
</Typography>
|
|
589
|
-
</
|
|
590
|
-
|
|
588
|
+
</Box>
|
|
589
|
+
|
|
591
590
|
{/* Date Range Pickers */}
|
|
592
|
-
<
|
|
591
|
+
<Box sx={{ width: { xs: '100%', sm: '50%', md: '33.33%' }, display: 'flex', gap: 2, mb: 8, justifyContent: 'flex-end', alignItems: 'center' }}>
|
|
593
592
|
{!startDate && !endDate && (
|
|
594
593
|
<>
|
|
595
594
|
<Button
|
|
@@ -703,18 +702,18 @@ export function DateRangeSalesTable({ designer, admin, loading, updateLoadingSta
|
|
|
703
702
|
</IconButton>
|
|
704
703
|
</Tooltip>
|
|
705
704
|
)}
|
|
706
|
-
</
|
|
705
|
+
</Box>
|
|
707
706
|
|
|
708
707
|
{/* Error Message */}
|
|
709
708
|
{error && (
|
|
710
|
-
<
|
|
709
|
+
<Box sx={{ width: '100%' }}>
|
|
711
710
|
<Typography variant="body2" sx={{ color: 'var(--red, red)', mb: 2 }}>{error}</Typography>
|
|
712
|
-
</
|
|
711
|
+
</Box>
|
|
713
712
|
)}
|
|
714
713
|
|
|
715
714
|
{/* Reconciliation Check - Only show for admin users */}
|
|
716
715
|
{admin && dateRangeSales.length > 0 && (
|
|
717
|
-
<
|
|
716
|
+
<Box sx={{ width: '100%', mb: 2 }}>
|
|
718
717
|
<Box
|
|
719
718
|
sx={{
|
|
720
719
|
display: 'inline-block',
|
|
@@ -780,9 +779,9 @@ export function DateRangeSalesTable({ designer, admin, loading, updateLoadingSta
|
|
|
780
779
|
</>
|
|
781
780
|
)}
|
|
782
781
|
</Box>
|
|
783
|
-
</
|
|
782
|
+
</Box>
|
|
784
783
|
)}
|
|
785
|
-
|
|
784
|
+
|
|
786
785
|
{/* Summary Dashboard and Analysis Components - only show when data is loaded */}
|
|
787
786
|
{!!dateRangeSales.length && (
|
|
788
787
|
<>
|
|
@@ -833,11 +832,12 @@ export function DateRangeSalesTable({ designer, admin, loading, updateLoadingSta
|
|
|
833
832
|
|
|
834
833
|
{/* Sales Table */}
|
|
835
834
|
{!!dateRangeSales.length && (
|
|
836
|
-
<
|
|
837
|
-
<
|
|
838
|
-
textAlign={"right"}
|
|
835
|
+
<Box sx={{ display: 'flex', flexWrap: 'wrap', width: '100%', pb: 24 }}>
|
|
836
|
+
<Box
|
|
839
837
|
sx={{
|
|
840
|
-
|
|
838
|
+
width: '100%',
|
|
839
|
+
textAlign: 'right',
|
|
840
|
+
opacity: !!dateRangeSales.length ? 1 : 0.25,
|
|
841
841
|
pointerEvents: !!dateRangeSales.length ? "" : "none",
|
|
842
842
|
display: "flex",
|
|
843
843
|
justifyContent: "flex-end",
|
|
@@ -859,45 +859,41 @@ export function DateRangeSalesTable({ designer, admin, loading, updateLoadingSta
|
|
|
859
859
|
fontWeight: 500,
|
|
860
860
|
}}
|
|
861
861
|
>
|
|
862
|
-
<
|
|
863
|
-
<
|
|
864
|
-
<
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
</IconButton>
|
|
895
|
-
</Tooltip>
|
|
896
|
-
</Grid>
|
|
897
|
-
<Grid item ml={1}>
|
|
862
|
+
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
|
863
|
+
<Tooltip title="Select columns">
|
|
864
|
+
<IconButton
|
|
865
|
+
size="small"
|
|
866
|
+
onClick={handleMenuClick}
|
|
867
|
+
sx={{
|
|
868
|
+
color: 'var(--white, white)',
|
|
869
|
+
pointerEvents: "auto",
|
|
870
|
+
'&:hover': {
|
|
871
|
+
opacity: 0.8
|
|
872
|
+
}
|
|
873
|
+
}}
|
|
874
|
+
>
|
|
875
|
+
<TuneIcon fontSize="small" />
|
|
876
|
+
</IconButton>
|
|
877
|
+
</Tooltip>
|
|
878
|
+
<Tooltip title="Download CSV">
|
|
879
|
+
<IconButton
|
|
880
|
+
size="small"
|
|
881
|
+
onClick={() => downloadSalesData(',', designer, selectedColumns)}
|
|
882
|
+
sx={{
|
|
883
|
+
color: 'var(--white, white)',
|
|
884
|
+
pointerEvents: "auto",
|
|
885
|
+
'&:hover': {
|
|
886
|
+
opacity: 0.8
|
|
887
|
+
}
|
|
888
|
+
}}
|
|
889
|
+
>
|
|
890
|
+
<DownloadIcon fontSize="small" />
|
|
891
|
+
</IconButton>
|
|
892
|
+
</Tooltip>
|
|
893
|
+
<Box sx={{ ml: 1 }}>
|
|
898
894
|
<strong style={{ color: 'var(--white, white)' }}>CSV</strong>
|
|
899
|
-
</
|
|
900
|
-
</
|
|
895
|
+
</Box>
|
|
896
|
+
</Box>
|
|
901
897
|
|
|
902
898
|
<Menu
|
|
903
899
|
anchorEl={anchorEl}
|
|
@@ -912,34 +908,30 @@ export function DateRangeSalesTable({ designer, admin, loading, updateLoadingSta
|
|
|
912
908
|
}
|
|
913
909
|
}}
|
|
914
910
|
>
|
|
915
|
-
<
|
|
916
|
-
<
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
}}
|
|
940
|
-
>All</Button>
|
|
941
|
-
</Grid>
|
|
942
|
-
</Grid>
|
|
911
|
+
<Box sx={{ display: 'flex' }}>
|
|
912
|
+
<Button
|
|
913
|
+
onClick={handleSelectNone}
|
|
914
|
+
size='small'
|
|
915
|
+
variant="contained"
|
|
916
|
+
elevation={0}
|
|
917
|
+
sx={{
|
|
918
|
+
borderRadius: 0,
|
|
919
|
+
width: "50%",
|
|
920
|
+
boxShadow: 0
|
|
921
|
+
}}
|
|
922
|
+
>None</Button>
|
|
923
|
+
<Button
|
|
924
|
+
onClick={handleSelectAll}
|
|
925
|
+
size='small'
|
|
926
|
+
variant="contained"
|
|
927
|
+
elevation={0}
|
|
928
|
+
sx={{
|
|
929
|
+
borderRadius: 0,
|
|
930
|
+
width: "50%",
|
|
931
|
+
boxShadow: 0
|
|
932
|
+
}}
|
|
933
|
+
>All</Button>
|
|
934
|
+
</Box>
|
|
943
935
|
{COLUMNS
|
|
944
936
|
.filter(col => !col.adminOnly || admin)
|
|
945
937
|
.map((column) => (
|
|
@@ -971,9 +963,9 @@ export function DateRangeSalesTable({ designer, admin, loading, updateLoadingSta
|
|
|
971
963
|
))}
|
|
972
964
|
</Menu>
|
|
973
965
|
</Box>
|
|
974
|
-
</
|
|
966
|
+
</Box>
|
|
975
967
|
|
|
976
|
-
<
|
|
968
|
+
<Box data-disabled={loading} sx={{ width: '100%', opacity: !!dateRangeSales.length ? 1 : 0.25, pointerEvents: !!dateRangeSales.length ? "" : "none" }}>
|
|
977
969
|
<DataGrid
|
|
978
970
|
id={`${slugify(designer.user, { lower: true, remove: /[*/+~.()'"!:@]/g, strict: true })}-date-range`}
|
|
979
971
|
rows={(() => {
|
|
@@ -1064,9 +1056,9 @@ export function DateRangeSalesTable({ designer, admin, loading, updateLoadingSta
|
|
|
1064
1056
|
}
|
|
1065
1057
|
}}
|
|
1066
1058
|
/>
|
|
1067
|
-
</
|
|
1068
|
-
</
|
|
1059
|
+
</Box>
|
|
1060
|
+
</Box>
|
|
1069
1061
|
)}
|
|
1070
|
-
</
|
|
1062
|
+
</Box>
|
|
1071
1063
|
);
|
|
1072
1064
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// License type list component displaying all license types and their sales data with percentage sorting capability
|
|
2
2
|
import React, { useState } from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { Typography, Box, Tooltip, FormControl, InputLabel, Select, MenuItem, Stack } from '@mui/material';
|
|
4
4
|
import ArrowUpwardIcon from '@mui/icons-material/ArrowUpward';
|
|
5
5
|
import ArrowDownwardIcon from '@mui/icons-material/ArrowDownward';
|
|
6
6
|
import styles from '../styles/sales-portal.module.scss';
|
|
@@ -59,16 +59,14 @@ export default function LicenseTypeList({ licenseTypeData, sales, loading, admin
|
|
|
59
59
|
};
|
|
60
60
|
|
|
61
61
|
return (
|
|
62
|
-
<
|
|
63
|
-
<
|
|
64
|
-
item
|
|
65
|
-
xs={12}
|
|
62
|
+
<Box className='license-type-section' sx={{ width: '100%' }}>
|
|
63
|
+
<Box
|
|
66
64
|
data-disabled={loading}
|
|
67
65
|
data-loading={loading}
|
|
68
66
|
sx={{
|
|
67
|
+
width: '100%',
|
|
69
68
|
margin: "20px 0 10px",
|
|
70
69
|
borderRadius: "4px",
|
|
71
|
-
flex: "none",
|
|
72
70
|
opacity: !!sales.length ? 1 : 0.25,
|
|
73
71
|
pointerEvents: !!sales.length ? "" : "none",
|
|
74
72
|
border: "1px solid var(--black, black)",
|
|
@@ -187,7 +185,7 @@ export default function LicenseTypeList({ licenseTypeData, sales, loading, admin
|
|
|
187
185
|
);
|
|
188
186
|
})}
|
|
189
187
|
</Box>
|
|
190
|
-
</
|
|
191
|
-
</
|
|
188
|
+
</Box>
|
|
189
|
+
</Box>
|
|
192
190
|
);
|
|
193
191
|
}
|