robobyte-front-builder 1.0.16 → 1.0.19

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.
@@ -1,20 +1,31 @@
1
- import React, { useEffect, useState } from 'react'
2
- import { Box, CircularProgress, Typography, Paper, IconButton, CardContent, Tooltip,Button } from '@mui/material'
3
- import { useRouter } from 'next/router'
1
+ import React, {useEffect, useState} from 'react'
2
+ import {Box, CircularProgress, Typography, Paper, IconButton, CardContent, Tooltip} from '@mui/material'
3
+ import {useRouter} from 'next/router'
4
4
  import SGrid from 'views/genericTable/SGrid'
5
- import { Endpoints, Services } from 'services/Endpoints'
5
+ import {Endpoints, Services} from 'services/Endpoints'
6
6
  import PermissionsSubjects from 'src/configs/Permissions/PermissionsSubjects.json'
7
- import { SettingsOutlined } from '@mui/icons-material'
7
+ import CardHeader from "@mui/material/CardHeader";
8
+ import Grid from "@mui/material/Grid";
9
+ import {Plus} from "mdi-material-ui";
10
+ import TAGGrid from "views/genericTable/TAGGrid";
11
+ import {SettingsOutlined} from "@mui/icons-material";
12
+ import UpdateReportPermissionDialog from "views/rolePermissions/UpdateReportPermissionDialog";
13
+ import {getReportSession} from 'src/services/helper/reportSessionHelper'
14
+ import BlankLayout from "src/@core/layouts/BlankLayout";
15
+ import ReportsCard from "src/pages/reportModule/reportBuilder/reportsPermissions";
16
+
8
17
 
9
18
  // make sure you’ve globally included the Alpine theme once in _app.js or your main stylesheet:
10
19
  // import 'ag-grid-community/styles/ag-grid.css'
11
20
  // import 'ag-grid-community/styles/ag-theme-alpine.css'
12
21
 
13
- const ReportViewer = params => {
22
+ const ReportViewer = (params) => {
14
23
  const router = useRouter()
15
24
  const {
16
25
  id,
17
26
  filter,
27
+ extraCols,
28
+ setOutGridApi,
18
29
  minimized,
19
30
  setData,
20
31
  pageId,
@@ -25,62 +36,108 @@ const ReportViewer = params => {
25
36
  columnsConfig,
26
37
  refresh,
27
38
  dataAsObject,
28
- sessionId
39
+ height,
40
+ sessionId,
41
+ globalParams,
42
+ isRerender = false,
43
+ updateRef
29
44
  } = params ?? router.query
30
45
  const [isLoading, setIsLoading] = useState(false)
31
46
  const [builderModel, setBuilderModel] = useState(null)
32
47
  const [builderMetadata, setBuilderMetadata] = useState(null)
33
48
  const [sessionPayload, setSessionPayload] = useState(null)
34
49
  const [payloadVersion, setPayloadVersion] = useState(0)
35
- console.log(filter)
50
+
36
51
  useEffect(() => {
37
- // Prefer window.name payload (set by opener) to avoid relying on session
52
+ // Prefer localStorage payload via sessionId (set by SGrid)
38
53
  try {
39
- if (typeof window !== 'undefined' && window.name) {
40
- const nm = window.name
41
- if (nm.startsWith('RB:')) {
42
- const b64 = nm.substring(3)
43
- try {
44
- const json = decodeURIComponent(escape(typeof atob !== 'undefined' ? atob(b64) : b64))
45
- const payload = JSON.parse(json)
46
- setSessionPayload(payload)
47
- // Clear the name to avoid reusing stale payload on internal navigations
48
- window.name = ''
49
- } catch (e) {
50
- console.warn('Failed to parse window.name payload', e)
54
+ if (typeof window !== 'undefined') {
55
+ const sId = sessionId || router.query?.sessionId;
56
+ if (sId) {
57
+ const payload = getReportSession(sId);
58
+ if (payload) {
59
+ setSessionPayload(payload);
60
+ console.log('Processed localStorage payload for sessionId:', sId);
61
+
62
+ return;
63
+ }
64
+ }
65
+ }
66
+
67
+ // Fallback: sessionStorage payload (set by SGrid)
68
+ try {
69
+ if (typeof window !== 'undefined') {
70
+ const stored = sessionStorage.getItem('RB_PAYLOAD');
71
+ if (stored) {
72
+ try {
73
+ const payload = JSON.parse(stored);
74
+ setSessionPayload(payload);
75
+ sessionStorage.removeItem('RB_PAYLOAD');
76
+ console.log('Processed and cleared sessionStorage payload');
77
+
78
+ return; // Exit early if we found a payload in session
79
+ } catch (e) {
80
+ console.warn('Failed to parse sessionStorage payload', e);
81
+ }
51
82
  }
52
83
  }
84
+ } catch (e) {
85
+ console.error('Failed to load sessionStorage payload', e)
53
86
  }
87
+
54
88
  // Fallback: payload via query "payload" (URL-encoded JSON)
55
- const qp = router.query?.payload
56
- if (!sessionPayload && qp) {
89
+ const qp = router.query?.payload;
90
+ if (qp) {
57
91
  try {
58
- const payload = JSON.parse(decodeURIComponent(qp))
59
- setSessionPayload(payload)
60
- } catch {}
92
+ const payload = JSON.parse(decodeURIComponent(qp));
93
+ setSessionPayload(payload);
94
+
95
+ return;
96
+ } catch {
97
+ }
98
+ }
99
+
100
+ // If we reach here, no payload was found in this navigation
101
+ // We should probably clear sessionPayload IF the current URL doesn't have it
102
+ // but only if it was previously set.
103
+ if (sessionPayload) {
104
+ setSessionPayload(null);
61
105
  }
62
106
  } catch (e) {
63
- console.error('Failed to load window.name payload', e)
107
+ console.error('Failed to load report payload', e)
64
108
  }
65
- console.log(router.query?.payload)
66
- }, [router.query?.payload])
109
+ }, [router.asPath, id, pageId, router.query?.pageId, sessionId, router.query?.sessionId])
67
110
 
68
111
  const handleGetReport = async (reportId, reportPageId) => {
69
112
  setIsLoading(true)
70
113
  try {
71
- const { data } = await Services.PostService(
114
+ const {data} = await Services.PostService(
72
115
  Endpoints.ReportBuilder.Post.GetReportDetails,
73
116
  false,
74
117
  {},
75
- { id: reportId, pageId: reportPageId }
118
+ {id: reportId, pageId: reportPageId}
76
119
  )
77
120
  const localBuilderModel = JSON.parse(data.value)
78
- setBuilderModel({ ...localBuilderModel, id: data.id })
121
+ if (globalParams != null && localBuilderModel?.selectionParams != null) {
122
+ localBuilderModel.selectionParams = localBuilderModel.selectionParams.map((param, idx) => {
123
+ if (globalParams.hasOwnProperty(idx)) {
124
+ return {...param, value: globalParams[idx]}
125
+ }
126
+ return param
127
+ })
128
+ }
129
+ localBuilderModel.filter = localBuilderModel.filter ?? {}
130
+ localBuilderModel.filter.LocalTfilter = localBuilderModel.filter?.LocalTfilter?.map(x => ({
131
+ ...x,
132
+ isMainFilter: true
133
+ })) ?? []
134
+ console.log(localBuilderModel)
135
+ setBuilderModel({...localBuilderModel, id: data.id})
79
136
  setBuilderMetadata({
80
137
  id: data.id,
81
138
  name: data.name,
82
139
  description: data.description,
83
- isNew: false
140
+ isNew: false,
84
141
  })
85
142
  } catch (err) {
86
143
  console.error(err)
@@ -90,24 +147,24 @@ const ReportViewer = params => {
90
147
  }
91
148
 
92
149
  useEffect(() => {
93
- console.log(sessionPayload)
94
- // bump version when payload externalFilter or pageId changes to force SGrid remount
95
- try {
96
- const sig = JSON.stringify({ ef: sessionPayload?.externalFilter ?? null, p: sessionPayload?.pageId ?? null })
97
- setPayloadVersion(v => v + 1)
98
- } catch {}
99
150
  // Load report when id or pageId changes; prefer session payload pageId if available
100
- let reportId = id ?? router.query?.id
101
- const pId = sessionPayload?.pageId != null ? sessionPayload.pageId : pageId
102
- if (reportId || pId) handleGetReport(reportId, pId)
103
- }, [id, router.query?.id, pageId, sessionPayload?.pageId, JSON.stringify(sessionPayload?.externalFilter)])
151
+ const targetPageId = sessionPayload?.pageId || pageId || router.query?.pageId;
152
+ const targetId = sessionPayload?.id || id || router.query?.id;
153
+
154
+ if (targetPageId || targetId) {
155
+ handleGetReport(targetId, targetPageId)
156
+ }
157
+
158
+ // bump version when payload changes to force SGrid remount
159
+ setPayloadVersion(v => v + 1);
160
+ }, [id, router.query?.id, pageId, router.query?.pageId, sessionPayload])
104
161
 
105
162
  return (
106
163
  <Box
107
164
  sx={{
108
- display: 'block',
165
+ display: 'flex',
109
166
  width: '100%',
110
- p: minimized !== true ? 2 : 0
167
+ p: minimized !== true ? 2 : 0,
111
168
  }}
112
169
  >
113
170
  {isLoading ? (
@@ -115,54 +172,47 @@ const ReportViewer = params => {
115
172
  sx={{
116
173
  display: 'flex',
117
174
  alignItems: 'center',
118
- justifyContent: 'center'
175
+ justifyContent: 'center',
119
176
  }}
120
177
  >
121
- <CircularProgress />
178
+ <CircularProgress/>
122
179
  </Box>
123
180
  ) : !builderModel ? (
124
- <Box textAlign='center' mt={8}>
125
- <Typography variant='subtitle1' color='text.secondary'>
181
+ <Box textAlign="center" mt={8}>
182
+ <Typography variant="subtitle1" color="text.secondary">
126
183
  No report selected
127
184
  </Typography>
128
185
  </Box>
129
186
  ) : (
130
187
  <>
131
- <Box
132
- display='flex'
133
- gap={1}
134
- flexDirection={'column'}
135
- sx={{
136
- width: '100%',
137
- backgroundColor: 'white',
138
- borderRadius: 2,
139
- boxShadow: minimized !== true && '0 4px 12px rgba(0,0,0,0.08)' // subtle custom shadow
140
- }}
141
- >
142
- {minimized !== true && noHeader !== true && (
143
- <Box display='flex' justifyContent={'space-between'} alignItems={'center'} gap={1} sx={{ p: 2 }}>
144
- <Typography variant='subtitle1' color='text.secondary'>
145
- {builderMetadata?.name ?? ''}
146
- </Typography>
147
- <Tooltip title={'Studio'}>
148
- <IconButton
149
- size={'small'}
150
- onClick={() => {
151
- router.push({ pathname: '/reportBuilder', query: { id: id ?? router.query?.id } })
152
- }}
153
- >
154
- <SettingsOutlined color={'primary'} />
155
- </IconButton>
156
- </Tooltip>
157
- </Box>
158
- )}
159
- <Box display={'flex'} alignItems='center' gap={1} width={'100%'}>
188
+ <Box display="flex" gap={1} flexDirection={'column'} sx={{
189
+ width: '100%',
190
+ backgroundColor: 'white', borderRadius: 2,
191
+ boxShadow: minimized !== true && '0 4px 12px rgba(0,0,0,0.08)', // subtle custom shadow
192
+ }}>
193
+ {(minimized !== true && noHeader !== true) &&
194
+ <Box display="flex" justifyContent={'space-between'} alignItems={'center'} gap={1} sx={{p: 2}}>
195
+ <Typography variant="subtitle1" color="text.secondary">{builderMetadata?.name ?? ""}</Typography>
196
+ {/*<Tooltip title={'Studio'}>*/}
197
+ {/* <IconButton*/}
198
+ {/* size={'small'}*/}
199
+ {/* onClick={() => {*/}
200
+ {/* router.push({pathname: '/reportModule/reportBuilder', query: {id: id ?? router.query?.id}})*/}
201
+ {/* }}*/}
202
+ {/* >*/}
203
+ {/* <SettingsOutlined color={'primary'}/>*/}
204
+ {/* </IconButton>*/}
205
+ {/*</Tooltip>*/}
206
+ </Box>}
207
+ <Box display={'flex'} alignItems="center" gap={1} width={'100%'}>
160
208
  <SGrid
161
209
  key={`rv-${payloadVersion}`}
162
210
  minimized={minimized}
211
+ extraCols={extraCols}
163
212
  builderModel={builderModel}
164
213
  setData={setData}
165
214
  isSingle={isSingle}
215
+ setOutGridApi={setOutGridApi}
166
216
  externalTimer={externalTimer}
167
217
  actions={actions}
168
218
  reportTitle={builderMetadata?.name}
@@ -170,6 +220,11 @@ const ReportViewer = params => {
170
220
  columnsConfig={columnsConfig ?? []}
171
221
  refresh={refresh}
172
222
  dataAsObject={dataAsObject}
223
+ height={height ?? '85vh'}
224
+ isRerender={isRerender}
225
+ // uniqueIdPath={'Id'}
226
+ // noPurge={true}
227
+ updateRef ={updateRef}
173
228
  />
174
229
  </Box>
175
230
  </Box>
@@ -181,7 +236,7 @@ const ReportViewer = params => {
181
236
 
182
237
  ReportViewer.acl = {
183
238
  action: 'view',
184
- subject: PermissionsSubjects.ReportBuilder
239
+ subject: PermissionsSubjects.Free,
185
240
  }
186
-
241
+ ReportViewer.getLayout = page => <BlankLayout>{page}</BlankLayout>
187
242
  export default ReportViewer
@@ -9,24 +9,34 @@ import {
9
9
  IconButton,
10
10
  Button,
11
11
  Card,
12
- CardContent, MenuItem, Select, FormControl, InputLabel
12
+ CardContent, MenuItem, Select, FormControl, InputLabel, Dialog
13
13
  } from '@mui/material'
14
14
  import SearchIcon from '@mui/icons-material/Search'
15
15
  import ClearIcon from '@mui/icons-material/Clear'
16
16
  import {Endpoints, Services} from 'services/Endpoints'
17
17
  import PermissionsSubjects from 'src/configs/Permissions/PermissionsSubjects.json'
18
- import {EditOutlined} from "@mui/icons-material";
18
+ import {EditOutlined, SettingsOutlined} from "@mui/icons-material";
19
+ import DriverRequestStatus from "services/enums/DriverRequestStatusEnum";
19
20
  import Grid from "@mui/material/Grid";
20
21
  import ReportBuilderTypeEnum from "services/enums/ReportBuilderTypeEnum";
22
+ import UpdateRangeProductPriceDialog from "views/productPrice/UpdateRangeProductPriceDialog";
23
+ import handleChange from "services/helper/handleChange";
24
+ import UpdateReportPermissionDialog from "views/rolePermissions/UpdateReportPermissionDialog";
25
+
21
26
 
22
27
  const ReportsList = () => {
23
28
  const router = useRouter()
24
29
  const [search, setSearch] = useState('')
25
30
  const [reports, setReports] = useState([])
31
+ const [selectedChildRow, setSelectedChildRow] = useState()
26
32
  const [filter, setFilter] = useState({
27
33
  type : 'Report',
28
34
  })
29
-
35
+ const [openDialogs, setOpenDialogs] = useState({
36
+ confirm: false,
37
+ PermissionReport: false,
38
+ CustomFilter: false,
39
+ })
30
40
 
31
41
  const handleGetReports = async () => {
32
42
  try {
@@ -48,10 +58,15 @@ const ReportsList = () => {
48
58
  handleGetReports()
49
59
  }, [])
50
60
 
61
+ const handleToggleDialogs = dialog => {
62
+ handleChange(setOpenDialogs, dialog, !openDialogs[dialog])
63
+ }
64
+
51
65
  const filtered = useMemo(() => {
52
66
  if (!search) return reports
53
67
  return reports.filter(r =>
54
- (r.name || '').toLowerCase().includes(search.toLowerCase())
68
+ (r.name || '').toLowerCase().includes(search.toLowerCase()) ||
69
+ (r.pageId || '').toLowerCase().includes(search.toLowerCase())
55
70
  )
56
71
  }, [search, reports])
57
72
 
@@ -62,12 +77,12 @@ const ReportsList = () => {
62
77
  return (
63
78
  <Box p={4} maxWidth={800} mx="auto">
64
79
  {/* Header */}
65
- <Box display="flex" sx={{width:'100%'}} justifyContent="space-between" alignItems="center" mb={3}>
66
- <Grid container sx={{width:'100%'}} >
67
- <Grid item size={8}>
80
+ <Box display="flex" justifyContent="space-between" alignItems="center" mb={3}>
81
+ <Grid container>
82
+ <Grid size={{ xs: 8 }}>
68
83
  <Typography variant="h4">All Reports</Typography>
69
84
  </Grid>
70
- <Grid item size={4}>
85
+ <Grid size={{ xs: 4 }}>
71
86
  <Box sx={{display:'flex'}}>
72
87
  <FormControl fullWidth>
73
88
  <InputLabel id='demo-simple-select-label'>النوع</InputLabel>
@@ -92,9 +107,9 @@ const ReportsList = () => {
92
107
  ))}
93
108
  </Select>
94
109
  </FormControl>
95
- <Button variant="contained" sx={{ml:3}} onClick={() => router.push('/reportModule/reportBuilder')}>
96
- New
97
- </Button>
110
+ <Button variant="contained" sx={{ml:3}} onClick={() => router.push('/reportModule/reportBuilder')}>
111
+ New
112
+ </Button>
98
113
  </Box>
99
114
  </Grid>
100
115
  </Grid>
@@ -133,6 +148,18 @@ const ReportsList = () => {
133
148
  {filtered.length > 0 ? (
134
149
  filtered.map(report => (
135
150
  <Card key={report.id} variant="outlined">
151
+ <Box sx={{display: 'flex', justifyContent: 'end'}}>
152
+ <IconButton
153
+ size={'small'}
154
+ onClick={() => {
155
+ setSelectedChildRow(report)
156
+ handleToggleDialogs('PermissionReport')
157
+ }}
158
+ >
159
+ <SettingsOutlined color={'primary'}/>
160
+ </IconButton>
161
+ </Box>
162
+
136
163
  <CardContent>
137
164
  <Typography variant="h6" color="primary">
138
165
  {report.name}
@@ -157,6 +184,9 @@ const ReportsList = () => {
157
184
  </Typography>
158
185
 
159
186
  </Box>
187
+ <Typography variant="caption">
188
+ {report.pageId}
189
+ </Typography>
160
190
  <Box mt={2} display="flex" alignItems="center" gap={1}>
161
191
  <Button
162
192
  size="small"
@@ -186,6 +216,16 @@ const ReportsList = () => {
186
216
  )}
187
217
  </Box>
188
218
  </Paper>
219
+ <Dialog
220
+ fullWidth
221
+ open={openDialogs.PermissionReport}
222
+ maxWidth='md'
223
+ scroll='body'
224
+ onClose={() => handleToggleDialogs('PermissionReport')}
225
+ >
226
+ <UpdateReportPermissionDialog handleToggleDialogs={handleToggleDialogs} report={selectedChildRow}/>
227
+ </Dialog>
228
+
189
229
  </Box>
190
230
  )
191
231
  }
@@ -0,0 +1,127 @@
1
+ // ** React Imports
2
+ // ** Next Import
3
+
4
+ // ** MUI Imports
5
+ import Box from '@mui/material/Box'
6
+ import Grid from '@mui/material/Grid'
7
+ import Typography from '@mui/material/Typography'
8
+ import CardHeader from '@mui/material/CardHeader'
9
+ // ** Icons Imports
10
+ import {CloudUploadOutline, Delete, DeleteCircle, DotsVerticalCircleOutline, Plus} from 'mdi-material-ui'
11
+ // ** Store Imports
12
+ // ** Custom Components Imports
13
+ import {useEffect, useState, useContext, useMemo} from 'react'
14
+ import handleChange from 'src/services/helper/handleChange'
15
+ import {Avatar, Button, ButtonGroup, Card, CardContent, Checkbox, Dialog, IconButton, Popover} from '@mui/material'
16
+ import ReportViewer from "src/pages/reportBuilder/reportViewer";
17
+ import PermissionsSubjects from "src/configs/Permissions/PermissionsSubjects.json";
18
+ import {AuthContext} from "context/AuthContext";
19
+ import CompanyDeliveryLayout from "src/layouts/CompanyDeliveryLayout";
20
+ import BlankLayout from "src/@core/layouts/BlankLayout";
21
+ // ** Utils Import
22
+
23
+ // ** Actions Imports
24
+
25
+ // ** Custom Components Imports
26
+
27
+ const pageMetaData = {
28
+ id: '157d6ea7-3572-4fef-9f16-7e5b7e552023'
29
+ }
30
+ const ReportsCard = () => {
31
+ // ** State
32
+
33
+ const authContext = useContext(AuthContext)
34
+
35
+ const [anchorEl, setAnchorEl] = useState(null)
36
+ const [selectedChildRow, setSelectedChildRow] = useState()
37
+ const filter = useMemo(() => {
38
+ return {
39
+ fixedTFilter: [{
40
+ isOrList: true,
41
+ method: 'Equals',
42
+ path: 'PermissionRoleId',
43
+ value: authContext?.user?.roleIds ?? []
44
+ }]
45
+ }
46
+ }
47
+ , [authContext])
48
+
49
+ const [openDialogs, setOpenDialogs] = useState({
50
+ image: false,
51
+ banner: false,
52
+ updatebanner: false,
53
+ confirm: false,
54
+ filter: false,
55
+ notification: false,
56
+ notify: false
57
+ })
58
+
59
+ // ** States
60
+ const actions = (params) => {
61
+ return <Box sx={{display: 'flex', alignItems: 'center'}}>
62
+ <IconButton
63
+ sx={{color: 'primary.light'}}
64
+ onClick={e => {
65
+ setAnchorEl(e.currentTarget)
66
+ setSelectedChildRow(params.data)
67
+ }}
68
+ >
69
+ <DotsVerticalCircleOutline/>
70
+ </IconButton>
71
+ </Box>
72
+ }
73
+
74
+
75
+ function handleFilterChange(field, value) {
76
+ handleChange(setFilter, field, value)
77
+ }
78
+
79
+ useEffect(() => {
80
+
81
+ }, [])
82
+
83
+ const handleToggleDialogs = dialog => {
84
+ handleChange(setOpenDialogs, dialog, !openDialogs[dialog])
85
+ }
86
+
87
+ return (
88
+ <Card>
89
+ <Grid container>
90
+ <Grid size={{ xs: 12 }}>
91
+ <CardHeader
92
+ title={
93
+ <Box>
94
+ <Typography variant='h6'>التقارير</Typography>
95
+
96
+ </Box>
97
+ }
98
+ sx={{pb: 4, '& .MuiCardHeader-title': {letterSpacing: '.15px'}}}
99
+ action={
100
+ <Grid container spacing={1} size={{ xs: 12 }}>
101
+
102
+ </Grid>
103
+ }
104
+ />
105
+
106
+ <Grid container spacing={3}>
107
+ <ReportViewer
108
+ noHeader={true}
109
+ pageId={pageMetaData.id}
110
+ filter={filter}
111
+ actions={actions}
112
+ height={'80vh'}
113
+ />
114
+
115
+ </Grid>
116
+ </Grid>
117
+ </Grid>
118
+ </Card>
119
+
120
+ )
121
+ }
122
+ ReportsCard.acl = {
123
+ action: 'view',
124
+ subject: PermissionsSubjects.Free
125
+ };
126
+ ReportsCard.getLayout = page => <BlankLayout>{page}</BlankLayout>
127
+ export default ReportsCard