robobyte-front-builder 1.0.0 → 1.0.3
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 +10 -20
- package/src/context/AuthContext.js +14 -172
- package/src/context/SystemContext.js +2 -1
- package/src/lib/index.js +9 -1
- package/src/lib/providers/RoboByteFrontBuilderProvider.jsx +63 -31
- package/src/services/ApiURL.js +11 -0
- package/src/services/DeleteService.js +3 -6
- package/src/services/Endpoints.js +6 -4
- package/src/services/GetService.js +3 -6
- package/src/services/PatchService.js +3 -6
- package/src/services/PostService.js +3 -6
- package/src/services/StreamService.js +3 -6
- package/src/services/UpdateService.js +3 -6
- package/src/services/auth/AuthService.js +5 -47
- package/src/services/auth/GetUsersService.js +5 -38
- package/src/services/auth/PostRegisterUser.js +5 -29
- package/src/services/auth/PostResetPasswordService.js +5 -28
- package/src/services/auth/PutAccountService.js +5 -29
- package/src/services/auth/PutRefreshToken.js +5 -69
- package/src/services/auth/RefreshToken.js +5 -0
- package/src/services/config.js +103 -0
- package/src/views/builder/viewer/renderers/RichTextRenderer.jsx +16 -3
- package/src/views/genericTable/cellRenderers/imageRenderer.js +0 -1
- package/src/views/genericTable/template/addTemplate.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "robobyte-front-builder",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "RoboByte low-code UI builder, Report builder, and navigation extension system",
|
|
5
5
|
"main": "src/lib/index.js",
|
|
6
6
|
"files": [
|
|
@@ -30,9 +30,16 @@
|
|
|
30
30
|
"react": ">=18",
|
|
31
31
|
"react-dom": ">=18",
|
|
32
32
|
"next": ">=13",
|
|
33
|
-
"@mui/material": ">=
|
|
34
|
-
"@mui/icons-material": ">=
|
|
33
|
+
"@mui/material": ">=7",
|
|
34
|
+
"@mui/icons-material": ">=7",
|
|
35
|
+
"@mui/lab": ">=7",
|
|
36
|
+
"@mui/system": ">=7",
|
|
37
|
+
"@mui/x-data-grid": ">=7",
|
|
38
|
+
"@mui/x-date-pickers": ">=7",
|
|
39
|
+
"@mui/x-tree-view": ">=7",
|
|
40
|
+
"@emotion/cache": ">=11",
|
|
35
41
|
"@emotion/react": ">=11",
|
|
42
|
+
"@emotion/server": ">=11",
|
|
36
43
|
"@emotion/styled": ">=11",
|
|
37
44
|
"axios": ">=1"
|
|
38
45
|
},
|
|
@@ -47,10 +54,6 @@
|
|
|
47
54
|
"@dnd-kit/core": "^6.3.1",
|
|
48
55
|
"@dnd-kit/sortable": "^10.0.0",
|
|
49
56
|
"@dnd-kit/utilities": "^3.2.2",
|
|
50
|
-
"@emotion/cache": "11.11.0",
|
|
51
|
-
"@emotion/react": "^11.14.0",
|
|
52
|
-
"@emotion/server": "11.11.0",
|
|
53
|
-
"@emotion/styled": "^11.14.0",
|
|
54
57
|
"@fullcalendar/common": "5.11.5",
|
|
55
58
|
"@fullcalendar/core": "6.1.7",
|
|
56
59
|
"@fullcalendar/daygrid": "6.1.7",
|
|
@@ -59,17 +62,8 @@
|
|
|
59
62
|
"@fullcalendar/react": "6.1.7",
|
|
60
63
|
"@fullcalendar/timegrid": "6.1.7",
|
|
61
64
|
"@hookform/resolvers": "3.1.0",
|
|
62
|
-
"@material-ui/core": "^4.12.4",
|
|
63
65
|
"@microsoft/signalr": "^8.0.0",
|
|
64
66
|
"@monaco-editor/react": "^4.7.0",
|
|
65
|
-
"@mui/icons-material": "^7.1.0",
|
|
66
|
-
"@mui/lab": "^7.0.0-beta.12",
|
|
67
|
-
"@mui/material": "^7.1.0",
|
|
68
|
-
"@mui/styled-engine-sc": "^6.0.0-alpha.18",
|
|
69
|
-
"@mui/system": "^7.1.0",
|
|
70
|
-
"@mui/x-data-grid": "^8.5.0",
|
|
71
|
-
"@mui/x-date-pickers": "^5.0.0",
|
|
72
|
-
"@mui/x-tree-view": "^8.5.0",
|
|
73
67
|
"@popperjs/core": "2.11.7",
|
|
74
68
|
"@react-google-maps/api": "^2.19.2",
|
|
75
69
|
"@reduxjs/toolkit": "1.9.5",
|
|
@@ -79,7 +73,6 @@
|
|
|
79
73
|
"ag-grid-react": "^33.3.2",
|
|
80
74
|
"apexcharts-clevision": "3.28.5",
|
|
81
75
|
"aws-amplify": "^5.3.13",
|
|
82
|
-
"axios": "1.4.0",
|
|
83
76
|
"axios-mock-adapter": "1.21.4",
|
|
84
77
|
"babel-eslint": "10.1.0",
|
|
85
78
|
"chart.js": "4.3.0",
|
|
@@ -105,21 +98,18 @@
|
|
|
105
98
|
"mdi-material-ui": "7.7.0",
|
|
106
99
|
"moment": "^2.30.1",
|
|
107
100
|
"moment-timezone": "^0.5.47",
|
|
108
|
-
"next": "^15.1.8",
|
|
109
101
|
"notistack": "^3.0.2",
|
|
110
102
|
"nprogress": "0.2.0",
|
|
111
103
|
"numeral": "^2.0.6",
|
|
112
104
|
"payment": "2.4.6",
|
|
113
105
|
"prismjs": "1.29.0",
|
|
114
106
|
"prop-types": "^15.8.1",
|
|
115
|
-
"react": "^19.1.0",
|
|
116
107
|
"react-apexcharts": "1.4.0",
|
|
117
108
|
"react-beautiful-dnd": "13.1.1",
|
|
118
109
|
"react-chartjs-2": "5.2.0",
|
|
119
110
|
"react-colorful": "^5.6.1",
|
|
120
111
|
"react-credit-cards": "0.8.3",
|
|
121
112
|
"react-datepicker": "4.11.0",
|
|
122
|
-
"react-dom": "^19.1.0",
|
|
123
113
|
"react-draft-wysiwyg": "1.15.0",
|
|
124
114
|
"react-dropzone": "14.2.3",
|
|
125
115
|
"react-hook-form": "7.43.9",
|
|
@@ -1,179 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* AuthContext — thin pass-through context for robobyte-front-builder.
|
|
3
|
+
*
|
|
4
|
+
* All authentication logic (login, logout, token refresh) lives in the
|
|
5
|
+
* HOST application. The host passes `user` and `accessToken` into
|
|
6
|
+
* RoboByteFrontBuilderProvider, which feeds them here.
|
|
7
|
+
*
|
|
8
|
+
* Components inside the package (TAGGrid, SGrid, SystemContext, etc.)
|
|
9
|
+
* read from this context the same way they always did — nothing changes
|
|
10
|
+
* for consumers, only the source of truth moved to the host.
|
|
11
|
+
*/
|
|
12
|
+
import { createContext } from 'react'
|
|
3
13
|
|
|
4
|
-
// ** Next Import
|
|
5
|
-
import { useRouter } from 'next/router'
|
|
6
|
-
import PutRefreshToken from 'services/auth/PutRefreshToken'
|
|
7
|
-
// ** Axios
|
|
8
|
-
import axios from 'axios'
|
|
9
|
-
|
|
10
|
-
// ** Config
|
|
11
|
-
import authConfig from 'src/configs/auth'
|
|
12
|
-
import { UsersEndpoints } from 'services/Endpoints/UsersEndpoints'
|
|
13
|
-
import { ApiURL } from 'services/Endpoints'
|
|
14
|
-
import { jwtDecode } from "jwt-decode";
|
|
15
|
-
import {ReportBuilderEndpoints} from "services/Endpoints/ReportBuilderEndpoints";
|
|
16
|
-
|
|
17
|
-
// ** Defaults
|
|
18
14
|
const defaultProvider = {
|
|
19
15
|
user: null,
|
|
20
16
|
accessToken: null,
|
|
21
|
-
loading: true,
|
|
22
|
-
setUser: () => null,
|
|
23
|
-
setLoading: () => Boolean,
|
|
24
|
-
isInitialized: false,
|
|
25
|
-
login: () => Promise.resolve(),
|
|
26
|
-
logout: () => Promise.resolve(),
|
|
27
|
-
setIsInitialized: () => Boolean,
|
|
28
|
-
register: () => Promise.resolve()
|
|
29
17
|
}
|
|
30
|
-
const AuthContext = createContext(defaultProvider)
|
|
31
|
-
const AuthProvider = ({ children }) => {
|
|
32
|
-
// ** States
|
|
33
|
-
const [user, setUser] = useState(defaultProvider.user)
|
|
34
|
-
const [loading, setLoading] = useState(defaultProvider.loading)
|
|
35
|
-
const [isInitialized, setIsInitialized] = useState(defaultProvider.isInitialized)
|
|
36
|
-
const [token, setToken] = useState()
|
|
37
|
-
// ** Hooks
|
|
38
|
-
const router = useRouter()
|
|
39
|
-
useEffect(() => {
|
|
40
|
-
const initAuth = async () => {
|
|
41
|
-
setIsInitialized(true)
|
|
42
|
-
const storedToken = window.localStorage.getItem(authConfig.storageTokenKeyName)
|
|
43
|
-
const storedRefreshToken = window.localStorage.getItem(authConfig.refreshToken)
|
|
44
|
-
if (storedToken) {
|
|
45
|
-
await PutRefreshToken()
|
|
46
|
-
setLoading(true)
|
|
47
|
-
await axios
|
|
48
|
-
.post(ApiURL + ReportBuilderEndpoints.Post.GenericGet.URL, {
|
|
49
|
-
tFilter : [
|
|
50
|
-
{
|
|
51
|
-
path :"Id",
|
|
52
|
-
method : "Equals",
|
|
53
|
-
value : window.localStorage.getItem(authConfig.storageUserId)
|
|
54
|
-
}
|
|
55
|
-
]
|
|
56
|
-
} ,{
|
|
57
|
-
headers: {
|
|
58
|
-
Authorization: 'Bearer ' + window.localStorage.getItem(authConfig.storageTokenKeyName),
|
|
59
|
-
'content-type': 'application/json'
|
|
60
|
-
},
|
|
61
|
-
params: {
|
|
62
|
-
sourceModel : 'AuthModule.Domain.AuthModels.ApplicationUser',
|
|
63
|
-
getType : 'Single',
|
|
64
|
-
page : 1,
|
|
65
|
-
pageSize: 1,
|
|
66
|
-
userId: window.localStorage.getItem(authConfig.storageUserId)
|
|
67
|
-
},
|
|
68
|
-
})
|
|
69
|
-
.then(async response => {
|
|
70
|
-
setLoading(false)
|
|
71
|
-
response.data.data = {
|
|
72
|
-
...response.data?.data,
|
|
73
|
-
permissions : [],
|
|
74
|
-
roles : []
|
|
75
|
-
}
|
|
76
|
-
setUser({ ...response.data?.data })
|
|
77
|
-
})
|
|
78
|
-
.catch(async e => {
|
|
79
|
-
setLoading(false)
|
|
80
|
-
handleLogout()
|
|
81
|
-
})
|
|
82
|
-
} else {
|
|
83
|
-
setLoading(false)
|
|
84
|
-
handleLogout()
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
initAuth()
|
|
88
|
-
}, [])
|
|
89
|
-
const handleLogin = (params, errorCallback) => {
|
|
90
|
-
|
|
91
|
-
axios
|
|
92
|
-
.post(ApiURL + UsersEndpoints.Post.Login.URL, params)
|
|
93
|
-
.then(async res => {
|
|
94
|
-
window.localStorage.setItem(authConfig.storageTokenKeyName, res.data.accessToken)
|
|
95
|
-
window.localStorage.setItem(authConfig.storageUserId, res.data.id)
|
|
96
|
-
window.localStorage.setItem(authConfig.refreshToken, res.data.refreshToken)
|
|
97
|
-
setToken(res.data.accessToken)
|
|
98
|
-
})
|
|
99
|
-
.then(() => {
|
|
100
|
-
axios
|
|
101
|
-
.post(ApiURL + ReportBuilderEndpoints.Post.GenericGet.URL, {
|
|
102
|
-
tFilter : [
|
|
103
|
-
{
|
|
104
|
-
path :"Id",
|
|
105
|
-
method : "Equals",
|
|
106
|
-
value : window.localStorage.getItem(authConfig.storageUserId)
|
|
107
|
-
}
|
|
108
|
-
]
|
|
109
|
-
} ,{
|
|
110
|
-
headers: {
|
|
111
|
-
Authorization: 'Bearer ' + window.localStorage.getItem(authConfig.storageTokenKeyName),
|
|
112
|
-
'content-type': 'application/json'
|
|
113
|
-
},
|
|
114
|
-
params: {
|
|
115
|
-
sourceModel : 'AuthModule.Domain.AuthModels.ApplicationUser',
|
|
116
|
-
getType : 'Single',
|
|
117
|
-
page : 1,
|
|
118
|
-
pageSize: 1,
|
|
119
|
-
userId: window.localStorage.getItem(authConfig.storageUserId)
|
|
120
|
-
},
|
|
121
|
-
})
|
|
122
|
-
.then(async response => {
|
|
123
|
-
const returnUrl = router.query.returnUrl
|
|
124
|
-
response.data.data = {
|
|
125
|
-
...response.data?.data,
|
|
126
|
-
permissions : [],
|
|
127
|
-
roles : []
|
|
128
|
-
}
|
|
129
|
-
setUser({ ...response.data?.data })
|
|
130
|
-
await window.localStorage.setItem('userData', JSON.stringify(response.data?.data))
|
|
131
|
-
const redirectURL = returnUrl && returnUrl !== '/' ? returnUrl : '/mainHome'
|
|
132
|
-
router.replace(redirectURL)
|
|
133
|
-
})
|
|
134
|
-
})
|
|
135
|
-
.catch(err => {
|
|
136
|
-
if (errorCallback) errorCallback(err)
|
|
137
|
-
})
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const handleLogout = () => {
|
|
141
|
-
setUser(null)
|
|
142
|
-
setIsInitialized(false)
|
|
143
|
-
window.localStorage.removeItem('userData')
|
|
144
|
-
window.localStorage.removeItem(authConfig.storageTokenKeyName)
|
|
145
|
-
window.localStorage.removeItem(authConfig.storageUserId)
|
|
146
|
-
window.localStorage.removeItem(authConfig.refreshToken)
|
|
147
|
-
router.push('/login')
|
|
148
|
-
}
|
|
149
18
|
|
|
150
|
-
|
|
151
|
-
axios
|
|
152
|
-
.post(authConfig.registerEndpoint, params)
|
|
153
|
-
.then(res => {
|
|
154
|
-
if (res.data.error) {
|
|
155
|
-
if (errorCallback) errorCallback(res.data.error)
|
|
156
|
-
} else {
|
|
157
|
-
handleLogin({ email: params.email, password: params.password })
|
|
158
|
-
}
|
|
159
|
-
})
|
|
160
|
-
.catch(err => (errorCallback ? errorCallback(err) : null))
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const values = {
|
|
164
|
-
user,
|
|
165
|
-
accessToken: token,
|
|
166
|
-
loading,
|
|
167
|
-
setUser,
|
|
168
|
-
setLoading,
|
|
169
|
-
isInitialized,
|
|
170
|
-
setIsInitialized,
|
|
171
|
-
login: handleLogin,
|
|
172
|
-
logout: handleLogout,
|
|
173
|
-
register: handleRegister
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
return <AuthContext.Provider value={values}>{children}</AuthContext.Provider>
|
|
177
|
-
}
|
|
19
|
+
const AuthContext = createContext(defaultProvider)
|
|
178
20
|
|
|
179
|
-
export { AuthContext
|
|
21
|
+
export { AuthContext }
|
|
@@ -6,7 +6,8 @@ import axios from 'axios'
|
|
|
6
6
|
// ** Axios
|
|
7
7
|
|
|
8
8
|
// ** Config
|
|
9
|
-
import {
|
|
9
|
+
import {Endpoints, Services} from 'services/Endpoints'
|
|
10
|
+
import {getBaseURL} from 'services/config'
|
|
10
11
|
import {useJsApiLoader} from '@react-google-maps/api'
|
|
11
12
|
import {AuthContext} from './AuthContext'
|
|
12
13
|
import handleChange from 'services/helper/handleChange'
|
package/src/lib/index.js
CHANGED
|
@@ -40,6 +40,11 @@
|
|
|
40
40
|
* ─────────────────────────────────────────────────────────────────────────────
|
|
41
41
|
*/
|
|
42
42
|
|
|
43
|
+
// ── Configuration ─────────────────────────────────────────────────────────────
|
|
44
|
+
// configureRoboByte({ baseURL, apiURL, getAccessToken, getUser })
|
|
45
|
+
// Or pass these as props to RoboByteFrontBuilderProvider (preferred).
|
|
46
|
+
export { configureRoboByte, getBaseURL, getApiURL, getAccessToken, getUser } from '../services/config'
|
|
47
|
+
|
|
43
48
|
// ── Navigation Extension API ──────────────────────────────────────────────────
|
|
44
49
|
// NavigationExtensionProvider : Wrap your app to enable nav injection
|
|
45
50
|
// useNavigationExtensionContext: Internal context accessor (used by the nav renderer)
|
|
@@ -72,4 +77,7 @@ export { default as ReportBuilderPage } from '../pages/reportModule/reportBuilde
|
|
|
72
77
|
// Useful when you need to read or drive builder state from the host app.
|
|
73
78
|
export { BuilderProvider, useBuilder } from '../context/BuilderContext'
|
|
74
79
|
export { SystemContext, SystemProvider } from '../context/SystemContext'
|
|
75
|
-
|
|
80
|
+
// AuthContext is a read-only pass-through — values come from the host via
|
|
81
|
+
// RoboByteFrontBuilderProvider's user / accessToken props.
|
|
82
|
+
// There is no AuthProvider in this package; use your own host auth provider.
|
|
83
|
+
export { AuthContext } from '../context/AuthContext'
|
|
@@ -1,56 +1,88 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* RoboByteFrontBuilderProvider
|
|
3
3
|
*
|
|
4
|
-
* Root provider for the
|
|
4
|
+
* Root provider for the robobyte-front-builder package.
|
|
5
5
|
* Wrap your host app's _app.js with this component.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
* nav items you pass via `navExtensions` (or register via useNavExtension)
|
|
9
|
-
* are merged into the sidebar automatically.
|
|
7
|
+
* ── Props ─────────────────────────────────────────────────────────────────
|
|
10
8
|
*
|
|
11
|
-
*
|
|
9
|
+
* baseURL Root URL of the API server, e.g. "https://api.yourapp.com/"
|
|
10
|
+
* apiURL /api prefix URL, e.g. "https://api.yourapp.com/api/"
|
|
11
|
+
* user The currently logged-in user object from your auth context.
|
|
12
|
+
* Used by builder components that need the current user's id.
|
|
13
|
+
* accessToken The current Bearer token string from your auth context.
|
|
14
|
+
* All robobyte service calls attach this as Authorization header.
|
|
15
|
+
* navExtensions Static nav items to inject into the sidebar (see below).
|
|
12
16
|
*
|
|
13
|
-
*
|
|
17
|
+
* ── Example (_app.js in Mazajk / any host Next.js app) ───────────────────
|
|
14
18
|
*
|
|
15
|
-
*
|
|
19
|
+
* // Inside AuthProvider, read your own auth context and bridge it in:
|
|
20
|
+
*
|
|
21
|
+
* function RoboByteBridge({ children }) {
|
|
22
|
+
* const auth = useContext(AuthContext) // YOUR app's auth context
|
|
16
23
|
* return (
|
|
17
24
|
* <RoboByteFrontBuilderProvider
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* icon: 'CogOutline', // any mdi-material-ui icon name
|
|
23
|
-
* type: 'static',
|
|
24
|
-
* path: '/settings',
|
|
25
|
-
* insertAt: 'end', // 'start' | 'end' | number | { afterId } | { beforeId }
|
|
26
|
-
* },
|
|
27
|
-
* {
|
|
28
|
-
* id: 'host-analytics',
|
|
29
|
-
* title: 'Analytics',
|
|
30
|
-
* icon: 'ChartBar',
|
|
31
|
-
* type: 'static',
|
|
32
|
-
* path: '/analytics',
|
|
33
|
-
* insertAt: { afterId: 'host-settings' },
|
|
34
|
-
* }
|
|
35
|
-
* ]}
|
|
25
|
+
* baseURL="https://api.yourapp.com/"
|
|
26
|
+
* apiURL="https://api.yourapp.com/api/"
|
|
27
|
+
* user={auth.user}
|
|
28
|
+
* accessToken={auth.accessToken}
|
|
36
29
|
* >
|
|
37
|
-
*
|
|
30
|
+
* {children}
|
|
38
31
|
* </RoboByteFrontBuilderProvider>
|
|
39
32
|
* )
|
|
40
33
|
* }
|
|
34
|
+
*
|
|
35
|
+
* export default function App({ Component, pageProps }) {
|
|
36
|
+
* return (
|
|
37
|
+
* <AuthProvider>
|
|
38
|
+
* <RoboByteBridge>
|
|
39
|
+
* <Component {...pageProps} />
|
|
40
|
+
* </RoboByteBridge>
|
|
41
|
+
* </AuthProvider>
|
|
42
|
+
* )
|
|
43
|
+
* }
|
|
41
44
|
*/
|
|
42
45
|
|
|
46
|
+
import { useMemo } from 'react'
|
|
43
47
|
import { NavigationExtensionProvider } from '../navigation/NavigationExtensionContext'
|
|
48
|
+
import { configureRoboByte } from '../../services/config'
|
|
49
|
+
import { AuthContext } from '../../context/AuthContext'
|
|
44
50
|
|
|
45
51
|
/**
|
|
46
|
-
* @param {
|
|
52
|
+
* @param {string} [baseURL] Root API server URL (with trailing slash)
|
|
53
|
+
* @param {string} [apiURL] /api prefix URL (with trailing slash)
|
|
54
|
+
* @param {object} [user] Current user from the host auth context
|
|
55
|
+
* @param {string} [accessToken] Current Bearer token from the host auth context
|
|
56
|
+
* @param {Object[]} [navExtensions] Static nav items to inject into the sidebar
|
|
47
57
|
* @param {ReactNode} children
|
|
48
58
|
*/
|
|
49
|
-
const RoboByteFrontBuilderProvider = ({
|
|
59
|
+
const RoboByteFrontBuilderProvider = ({
|
|
60
|
+
children,
|
|
61
|
+
baseURL,
|
|
62
|
+
apiURL,
|
|
63
|
+
user = null,
|
|
64
|
+
accessToken = null,
|
|
65
|
+
navExtensions = [],
|
|
66
|
+
}) => {
|
|
67
|
+
// Apply URL config synchronously before any child renders.
|
|
68
|
+
useMemo(() => {
|
|
69
|
+
if (baseURL || apiURL) {
|
|
70
|
+
configureRoboByte({ baseURL, apiURL })
|
|
71
|
+
}
|
|
72
|
+
}, [baseURL, apiURL])
|
|
73
|
+
|
|
74
|
+
// Auth context value — comes entirely from the host. No logic here.
|
|
75
|
+
const authValue = useMemo(
|
|
76
|
+
() => ({ user, accessToken }),
|
|
77
|
+
[user, accessToken]
|
|
78
|
+
)
|
|
79
|
+
|
|
50
80
|
return (
|
|
51
|
-
<
|
|
52
|
-
{
|
|
53
|
-
|
|
81
|
+
<AuthContext.Provider value={authValue}>
|
|
82
|
+
<NavigationExtensionProvider items={navExtensions}>
|
|
83
|
+
{children}
|
|
84
|
+
</NavigationExtensionProvider>
|
|
85
|
+
</AuthContext.Provider>
|
|
54
86
|
)
|
|
55
87
|
}
|
|
56
88
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ApiURL — backward-compat shim for auth services that import:
|
|
3
|
+
* import ApiURL from '../ApiURL'
|
|
4
|
+
* const url = ApiURL() + '/api/...'
|
|
5
|
+
*
|
|
6
|
+
* Returns the configured API base URL at call time so that host apps
|
|
7
|
+
* can override it via configureRoboByte() before the first request.
|
|
8
|
+
*/
|
|
9
|
+
import { getApiURL } from './config'
|
|
10
|
+
|
|
11
|
+
export default getApiURL
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import Axios from 'axios'
|
|
2
2
|
import { DataTypes } from './ContentTypes'
|
|
3
|
-
import {
|
|
4
|
-
import authConfig from 'src/configs/auth'
|
|
3
|
+
import { getApiURL, getAccessToken } from './config'
|
|
5
4
|
import toast from 'react-hot-toast'
|
|
6
|
-
import PutRefreshToken from './auth/PutRefreshToken'
|
|
7
5
|
|
|
8
6
|
export default async function DeleteService(endpoint, showToast, data, params) {
|
|
9
|
-
|
|
10
|
-
const accessToken = localStorage.getItem(authConfig.storageTokenKeyName)
|
|
7
|
+
const accessToken = getAccessToken()
|
|
11
8
|
let response = { status: 'Error', message: '' }
|
|
12
9
|
let result = null
|
|
13
10
|
let currentParams = {
|
|
@@ -16,7 +13,7 @@ export default async function DeleteService(endpoint, showToast, data, params) {
|
|
|
16
13
|
}
|
|
17
14
|
|
|
18
15
|
if (!data) return
|
|
19
|
-
const url =
|
|
16
|
+
const url = getApiURL() + endpoint.URL
|
|
20
17
|
|
|
21
18
|
const axiosConfig = {
|
|
22
19
|
method: 'delete',
|
|
@@ -23,10 +23,12 @@ import { ViewEndpoints } from './Endpoints/ViewEndpoints'
|
|
|
23
23
|
import { UiBuilderEndpoints } from 'services/Endpoints/UiBuilderEndpoints'
|
|
24
24
|
import { WidgetEndpoints } from 'services/Endpoints/WidgetEndpoints'
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
//
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
// BaseURL and ApiURL are now sourced from the config singleton so that
|
|
27
|
+
// host apps can override them via configureRoboByte() or the
|
|
28
|
+
// RoboByteFrontBuilderProvider baseURL / apiURL props.
|
|
29
|
+
// Use getBaseURL() / getApiURL() from 'services/config' inside functions
|
|
30
|
+
// rather than caching these at module-load time.
|
|
31
|
+
export { getBaseURL as BaseURL, getApiURL as ApiURL, configureRoboByte } from './config'
|
|
30
32
|
|
|
31
33
|
export const Services = {
|
|
32
34
|
GetService: GetService,
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
import Axios from 'axios'
|
|
2
2
|
import { DataTypes } from './ContentTypes'
|
|
3
|
-
import {
|
|
4
|
-
import authConfig from 'src/configs/auth'
|
|
3
|
+
import { getApiURL, getAccessToken } from './config'
|
|
5
4
|
import toast from 'react-hot-toast'
|
|
6
|
-
import PutRefreshToken from './auth/PutRefreshToken'
|
|
7
5
|
export default async function GetService(endpoint, showToast, data, params) {
|
|
8
|
-
|
|
9
|
-
const accessToken = localStorage.getItem(authConfig.storageTokenKeyName)
|
|
6
|
+
const accessToken = getAccessToken()
|
|
10
7
|
let response = { status: 'Error', message: '' }
|
|
11
8
|
let result = null
|
|
12
|
-
const url =
|
|
9
|
+
const url = getApiURL() + endpoint.URL
|
|
13
10
|
|
|
14
11
|
const axiosConfig = {
|
|
15
12
|
method: 'post',
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import Axios from 'axios'
|
|
2
2
|
import { DataTypes } from './ContentTypes'
|
|
3
|
-
import {
|
|
4
|
-
import authConfig from 'src/configs/auth'
|
|
3
|
+
import { getApiURL, getAccessToken } from './config'
|
|
5
4
|
import toast from 'react-hot-toast'
|
|
6
|
-
import PutRefreshToken from './auth/PutRefreshToken'
|
|
7
5
|
|
|
8
6
|
export default async function PatchService(endpoint, showToast, data, params) {
|
|
9
|
-
|
|
10
|
-
const accessToken = localStorage.getItem(authConfig.storageTokenKeyName)
|
|
7
|
+
const accessToken = getAccessToken()
|
|
11
8
|
let response = { status: 'Error', message: '' }
|
|
12
9
|
let result = null
|
|
13
10
|
let currentParams = {
|
|
@@ -22,7 +19,7 @@ export default async function PatchService(endpoint, showToast, data, params) {
|
|
|
22
19
|
...(endpoint.DataType == DataTypes.Body ? { ...data } : {})
|
|
23
20
|
}
|
|
24
21
|
if (!data) return
|
|
25
|
-
const url =
|
|
22
|
+
const url = getApiURL() + endpoint.URL
|
|
26
23
|
|
|
27
24
|
const axiosConfig = {
|
|
28
25
|
method: 'patch',
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import Axios from 'axios'
|
|
2
2
|
import { DataTypes } from './ContentTypes'
|
|
3
|
-
import {
|
|
4
|
-
import authConfig from 'src/configs/auth'
|
|
3
|
+
import { getApiURL, getAccessToken } from './config'
|
|
5
4
|
import toast from 'react-hot-toast'
|
|
6
|
-
import PutRefreshToken from './auth/PutRefreshToken'
|
|
7
5
|
|
|
8
6
|
export default async function PostService(endpoint, showToast, data, params) {
|
|
9
|
-
|
|
10
|
-
const accessToken = localStorage.getItem(authConfig.storageTokenKeyName)
|
|
7
|
+
const accessToken = getAccessToken()
|
|
11
8
|
|
|
12
9
|
|
|
13
10
|
let response = { status: 'Error', message: '' }
|
|
@@ -19,7 +16,7 @@ export default async function PostService(endpoint, showToast, data, params) {
|
|
|
19
16
|
let currnetData = endpoint.DataType == DataTypes.Form || endpoint.DataType == DataTypes.Body ? data : {}
|
|
20
17
|
|
|
21
18
|
if (!data) return
|
|
22
|
-
const url =
|
|
19
|
+
const url = getApiURL() + endpoint.URL
|
|
23
20
|
|
|
24
21
|
const axiosConfig = {
|
|
25
22
|
method: 'post',
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
import Axios from 'axios'
|
|
2
|
-
import {
|
|
3
|
-
import authConfig from 'src/configs/auth'
|
|
4
|
-
import PutRefreshToken from './auth/PutRefreshToken'
|
|
2
|
+
import { getApiURL, getAccessToken } from './config'
|
|
5
3
|
import toast from 'react-hot-toast'
|
|
6
4
|
import {DataTypes} from "services/ContentTypes";
|
|
7
5
|
|
|
8
6
|
export default async function StreamService(endpoint, showToast, data, params, api, progressCallback) {
|
|
9
|
-
|
|
10
|
-
const accessToken = localStorage.getItem(authConfig.storageTokenKeyName)
|
|
7
|
+
const accessToken = getAccessToken()
|
|
11
8
|
|
|
12
|
-
const url = api ??
|
|
9
|
+
const url = api ?? getApiURL() + endpoint.URL
|
|
13
10
|
|
|
14
11
|
let currentParams = {
|
|
15
12
|
...params,
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import Axios from 'axios'
|
|
2
2
|
import { DataTypes } from './ContentTypes'
|
|
3
|
-
import {
|
|
4
|
-
import authConfig from 'src/configs/auth'
|
|
3
|
+
import { getApiURL, getAccessToken } from './config'
|
|
5
4
|
import toast from 'react-hot-toast'
|
|
6
|
-
import PutRefreshToken from './auth/PutRefreshToken'
|
|
7
5
|
|
|
8
6
|
export default async function UpdateService(endpoint, showToast, data, params) {
|
|
9
|
-
|
|
10
|
-
const accessToken = localStorage.getItem(authConfig.storageTokenKeyName)
|
|
7
|
+
const accessToken = getAccessToken()
|
|
11
8
|
let response = { status: 'Error', message: '' }
|
|
12
9
|
let result = null
|
|
13
10
|
let currentParams = {
|
|
@@ -21,7 +18,7 @@ export default async function UpdateService(endpoint, showToast, data, params) {
|
|
|
21
18
|
...(endpoint.DataType == DataTypes.Body ? { ...data } : {})
|
|
22
19
|
}
|
|
23
20
|
if (!data) return
|
|
24
|
-
const url =
|
|
21
|
+
const url = getApiURL() + endpoint.URL
|
|
25
22
|
|
|
26
23
|
const axiosConfig = {
|
|
27
24
|
method: 'put',
|
|
@@ -1,47 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
let result = { status: "Error", message: "" };
|
|
7
|
-
|
|
8
|
-
if (!User) return;
|
|
9
|
-
const url = apiURL + `/api/Auth/Login`;
|
|
10
|
-
|
|
11
|
-
const axiosConfig = {
|
|
12
|
-
method: "post",
|
|
13
|
-
headers: {
|
|
14
|
-
"Content-Type": "application/json-patch+json",
|
|
15
|
-
},
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
try {
|
|
19
|
-
const resporone = await Axios.post(url, User, axiosConfig)
|
|
20
|
-
.then((r) => {
|
|
21
|
-
result = r.data;
|
|
22
|
-
})
|
|
23
|
-
.catch((r) => {
|
|
24
|
-
|
|
25
|
-
if (r.response && r.response.status == 400) {
|
|
26
|
-
result = {
|
|
27
|
-
status: "Error",
|
|
28
|
-
message: r.response.data,
|
|
29
|
-
};
|
|
30
|
-
} else if (r.response && r.response.status == 401) {
|
|
31
|
-
result = {
|
|
32
|
-
status: "Error",
|
|
33
|
-
message: "غير مخول بالدخول",
|
|
34
|
-
};
|
|
35
|
-
} else {
|
|
36
|
-
result = {
|
|
37
|
-
status: "Error",
|
|
38
|
-
message: "حدث خطأ في الاتصال مع الخادم",
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
} catch (error) {
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return result;
|
|
47
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* This file has been removed.
|
|
3
|
+
* Authentication is handled entirely by the host application.
|
|
4
|
+
* robobyte-front-builder no longer owns any auth logic.
|
|
5
|
+
*/
|
|
@@ -1,38 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
let result =null;
|
|
7
|
-
const apiURL = ApiURL() + '/api/Users/GetByUserRole';
|
|
8
|
-
|
|
9
|
-
if (!User )
|
|
10
|
-
return;
|
|
11
|
-
let currentFilter
|
|
12
|
-
if(filter){
|
|
13
|
-
currentFilter={...filter}
|
|
14
|
-
}else{
|
|
15
|
-
currentFilter={
|
|
16
|
-
page:1,
|
|
17
|
-
pageSize:100
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
const axiosConfig={
|
|
21
|
-
method: 'get',
|
|
22
|
-
headers: {
|
|
23
|
-
'Authorization': `Bearer ${User.accessToken}`,
|
|
24
|
-
'Content-Type': 'application/json-patch+json',
|
|
25
|
-
},params:{
|
|
26
|
-
...currentFilter
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
const response = await Axios.get(apiURL,axiosConfig);
|
|
31
|
-
if (response.status===200)
|
|
32
|
-
{
|
|
33
|
-
result = response.data;
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return result
|
|
38
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* This file has been removed.
|
|
3
|
+
* Authentication is handled entirely by the host application.
|
|
4
|
+
* robobyte-front-builder no longer owns any auth logic.
|
|
5
|
+
*/
|
|
@@ -1,29 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
let result =null;
|
|
8
|
-
const apiURL = ApiURL() + '/api/Auth/Register';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (!User || !data)
|
|
12
|
-
return;
|
|
13
|
-
const axiosConfig={
|
|
14
|
-
method: 'post',
|
|
15
|
-
headers: {
|
|
16
|
-
'Authorization': `Bearer ${User.accessToken}`,
|
|
17
|
-
'Content-Type': 'application/json-patch+json',
|
|
18
|
-
},
|
|
19
|
-
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const resporone = await Axios.post(apiURL,data,axiosConfig);
|
|
23
|
-
if (resporone.status===200)
|
|
24
|
-
{
|
|
25
|
-
result = resporone.data;
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
return result
|
|
29
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* This file has been removed.
|
|
3
|
+
* Authentication is handled entirely by the host application.
|
|
4
|
+
* robobyte-front-builder no longer owns any auth logic.
|
|
5
|
+
*/
|
|
@@ -1,28 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
let result =null;
|
|
7
|
-
const apiURL = ApiURL() + '/api/Auth/ResetPassword';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (!User || !data)
|
|
11
|
-
return;
|
|
12
|
-
const axiosConfig={
|
|
13
|
-
method: 'post',
|
|
14
|
-
headers: {
|
|
15
|
-
'Authorization': `Bearer ${User.accessToken}`,
|
|
16
|
-
'Content-Type': 'application/json-patch+json',
|
|
17
|
-
}
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const resporone = await Axios.post(apiURL,data,axiosConfig);
|
|
21
|
-
|
|
22
|
-
if (resporone.status===200)
|
|
23
|
-
{
|
|
24
|
-
result = resporone.data;
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
return result
|
|
28
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* This file has been removed.
|
|
3
|
+
* Authentication is handled entirely by the host application.
|
|
4
|
+
* robobyte-front-builder no longer owns any auth logic.
|
|
5
|
+
*/
|
|
@@ -1,29 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
if (!User || !data) return;
|
|
7
|
-
const apiURL = ApiURL() + `/api/Users/${data.id}`;
|
|
8
|
-
|
|
9
|
-
const axiosConfig = {
|
|
10
|
-
method: "put",
|
|
11
|
-
headers: {
|
|
12
|
-
Authorization: `Bearer ${User.accessToken}`,
|
|
13
|
-
"Content-Type": "application/json-patch+json",
|
|
14
|
-
},
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
try {
|
|
18
|
-
const resporone = await Axios.put(apiURL, data, axiosConfig);
|
|
19
|
-
|
|
20
|
-
if (resporone.status === 200) {
|
|
21
|
-
result = resporone.data;
|
|
22
|
-
}
|
|
23
|
-
throw resporone;
|
|
24
|
-
} catch (error) {
|
|
25
|
-
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return result;
|
|
29
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* This file has been removed.
|
|
3
|
+
* Authentication is handled entirely by the host application.
|
|
4
|
+
* robobyte-front-builder no longer owns any auth logic.
|
|
5
|
+
*/
|
|
@@ -1,69 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import authConfig from 'src/configs/auth'
|
|
7
|
-
import {Router} from 'next/router';
|
|
8
|
-
import {useRouter} from 'next/router';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const apiURL = BaseURL
|
|
12
|
-
|
|
13
|
-
const handleLogout = () => {
|
|
14
|
-
localStorage.removeItem('userData')
|
|
15
|
-
localStorage.removeItem('refreshToken')
|
|
16
|
-
localStorage.removeItem('userId')
|
|
17
|
-
localStorage.removeItem('accessToken')
|
|
18
|
-
|
|
19
|
-
window.location.href = '/login'
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export default async function PutRefreshToken() {
|
|
24
|
-
let token = localStorage.getItem(authConfig.storageTokenKeyName)
|
|
25
|
-
if (token == null || token == '') {
|
|
26
|
-
handleLogout()
|
|
27
|
-
}
|
|
28
|
-
let refreshToken = localStorage.getItem(authConfig.refreshToken)
|
|
29
|
-
let response = null;
|
|
30
|
-
|
|
31
|
-
function isTokenExpired(token) {
|
|
32
|
-
try {
|
|
33
|
-
const decodedToken = jwtDecode(token);
|
|
34
|
-
const expirationDate = new Date(decodedToken.exp * 1000);
|
|
35
|
-
return expirationDate < new Date();
|
|
36
|
-
} catch {
|
|
37
|
-
handleLogout()
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const istokenExpired = isTokenExpired(token)
|
|
43
|
-
if (istokenExpired) {
|
|
44
|
-
const url = apiURL + `api/Auth/Refresh-Token?refreshToken=${refreshToken}`;
|
|
45
|
-
const axiosConfig = {
|
|
46
|
-
method: 'put',
|
|
47
|
-
headers: {
|
|
48
|
-
|
|
49
|
-
'Content-Type': 'application/json-patch+json',
|
|
50
|
-
},
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
try {
|
|
54
|
-
response = await Axios.put(url, axiosConfig);
|
|
55
|
-
if (response.status == 200) {
|
|
56
|
-
localStorage.setItem(authConfig.storageTokenKeyName, response.data.accessToken)
|
|
57
|
-
} else {
|
|
58
|
-
handleLogout();
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
} catch (error) {
|
|
62
|
-
handleLogout();
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return
|
|
69
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* This file has been removed.
|
|
3
|
+
* Token refresh is handled entirely by the host application.
|
|
4
|
+
* robobyte-front-builder no longer owns any auth logic.
|
|
5
|
+
*/
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RoboByte Configuration
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth for API URLs and auth accessors.
|
|
5
|
+
* This module has NO imports from other local service files — it can
|
|
6
|
+
* never participate in a circular dependency.
|
|
7
|
+
*
|
|
8
|
+
* ── Usage in the host app ──────────────────────────────────────────────────
|
|
9
|
+
*
|
|
10
|
+
* // Option A — via RoboByteFrontBuilderProvider props (recommended):
|
|
11
|
+
* <RoboByteFrontBuilderProvider
|
|
12
|
+
* baseURL="https://api.yourapp.com/"
|
|
13
|
+
* apiURL="https://api.yourapp.com/api/"
|
|
14
|
+
* user={authUser}
|
|
15
|
+
* accessToken={authToken}
|
|
16
|
+
* >
|
|
17
|
+
*
|
|
18
|
+
* // Option B — imperative call once before rendering:
|
|
19
|
+
* import { configureRoboByte } from 'robobyte-front-builder'
|
|
20
|
+
* configureRoboByte({
|
|
21
|
+
* baseURL: 'https://api.yourapp.com/',
|
|
22
|
+
* apiURL: 'https://api.yourapp.com/api/',
|
|
23
|
+
* getAccessToken: () => localStorage.getItem('accessToken'),
|
|
24
|
+
* getUser: () => JSON.parse(localStorage.getItem('userData') || 'null'),
|
|
25
|
+
* })
|
|
26
|
+
*
|
|
27
|
+
* ─────────────────────────────────────────────────────────────────────────
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
const _config = {
|
|
31
|
+
baseURL: 'http://140.82.34.191:3400/',
|
|
32
|
+
apiURL: 'http://140.82.34.191:3400/api/',
|
|
33
|
+
|
|
34
|
+
// Default token reader — reads the key Mazajk (and most host apps) use.
|
|
35
|
+
// Override via configureRoboByte({ getAccessToken }) or via the provider prop.
|
|
36
|
+
getAccessToken: () => {
|
|
37
|
+
if (typeof window === 'undefined') return null
|
|
38
|
+
return localStorage.getItem('accessToken') ?? null
|
|
39
|
+
},
|
|
40
|
+
|
|
41
|
+
// Default user reader — parses the JSON object Mazajk stores in localStorage.
|
|
42
|
+
// Override via configureRoboByte({ getUser }) or via the provider prop.
|
|
43
|
+
getUser: () => {
|
|
44
|
+
if (typeof window === 'undefined') return null
|
|
45
|
+
try {
|
|
46
|
+
const raw = localStorage.getItem('userData')
|
|
47
|
+
return raw ? JSON.parse(raw) : null
|
|
48
|
+
} catch {
|
|
49
|
+
return null
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Configure robobyte-front-builder.
|
|
56
|
+
* All fields are optional — only the ones you pass will be updated.
|
|
57
|
+
*
|
|
58
|
+
* @param {Object} [options]
|
|
59
|
+
* @param {string} [options.baseURL] Root URL of the API server (trailing slash)
|
|
60
|
+
* @param {string} [options.apiURL] /api prefix URL (trailing slash)
|
|
61
|
+
* @param {Function} [options.getAccessToken] () => string | null — returns the current Bearer token
|
|
62
|
+
* @param {Function} [options.getUser] () => object | null — returns the current user object
|
|
63
|
+
*/
|
|
64
|
+
export function configureRoboByte({ baseURL, apiURL, getAccessToken, getUser } = {}) {
|
|
65
|
+
if (baseURL) {
|
|
66
|
+
_config.baseURL = baseURL.endsWith('/') ? baseURL : baseURL + '/'
|
|
67
|
+
}
|
|
68
|
+
if (apiURL) {
|
|
69
|
+
_config.apiURL = apiURL.endsWith('/') ? apiURL : apiURL + '/'
|
|
70
|
+
}
|
|
71
|
+
if (typeof getAccessToken === 'function') {
|
|
72
|
+
_config.getAccessToken = getAccessToken
|
|
73
|
+
}
|
|
74
|
+
if (typeof getUser === 'function') {
|
|
75
|
+
_config.getUser = getUser
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Returns the current base URL (e.g. "https://api.example.com/") */
|
|
80
|
+
export function getBaseURL() {
|
|
81
|
+
return _config.baseURL
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Returns the current API URL (e.g. "https://api.example.com/api/") */
|
|
85
|
+
export function getApiURL() {
|
|
86
|
+
return _config.apiURL
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Returns the current Bearer access token.
|
|
91
|
+
* Call this inside service functions — never cache the result at module level.
|
|
92
|
+
*/
|
|
93
|
+
export function getAccessToken() {
|
|
94
|
+
return _config.getAccessToken()
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Returns the current user object from the host app.
|
|
99
|
+
* Call this inside component render functions.
|
|
100
|
+
*/
|
|
101
|
+
export function getUser() {
|
|
102
|
+
return _config.getUser()
|
|
103
|
+
}
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
import { useRef } from 'react'
|
|
2
|
-
import
|
|
3
|
-
import 'suneditor/dist/css/suneditor.min.css'
|
|
2
|
+
import dynamic from 'next/dynamic'
|
|
4
3
|
import { Box, FormHelperText } from '@mui/material'
|
|
5
4
|
import ViewerComponentWrapper from '../ViewerComponentWrapper'
|
|
6
5
|
import { resolveProps } from 'services/builderHelper/resolveProps'
|
|
7
6
|
|
|
7
|
+
// SunEditor requires the DOM and loads suneditor/src/plugins at require-time,
|
|
8
|
+
// which is raw ESM with bare specifiers. Node.js 22's strict ESM resolver
|
|
9
|
+
// cannot resolve those extensionless imports at SSR, causing a fatal error.
|
|
10
|
+
// Dynamic import with ssr:false keeps the entire module out of the server bundle.
|
|
11
|
+
const SunEditor = dynamic(
|
|
12
|
+
() => {
|
|
13
|
+
// Import the CSS alongside the component so it's only loaded client-side too.
|
|
14
|
+
// Using require() inside the factory avoids a separate async CSS chunk.
|
|
15
|
+
require('suneditor/dist/css/suneditor.min.css')
|
|
16
|
+
return import('suneditor-react')
|
|
17
|
+
},
|
|
18
|
+
{ ssr: false }
|
|
19
|
+
)
|
|
20
|
+
|
|
8
21
|
export default function RichTextRenderer({ node, viewerContext }) {
|
|
9
22
|
const { data, form, updateFormValue, validationErrors } = viewerContext
|
|
10
23
|
const main = resolveProps(node, 'main', { form, data })
|
|
@@ -52,7 +65,7 @@ export default function RichTextRenderer({ node, viewerContext }) {
|
|
|
52
65
|
height: main.height || '300px',
|
|
53
66
|
placeholder: main.placeholder || 'Enter text here...',
|
|
54
67
|
disabled: main.disabled,
|
|
55
|
-
mode: main.mode || 'classic',
|
|
68
|
+
mode: main.mode || 'classic',
|
|
56
69
|
resizingBar: main.resizingBar !== false,
|
|
57
70
|
showPathLabel: main.showPathLabel !== false,
|
|
58
71
|
charCounter: main.charCounter !== false,
|
|
@@ -20,7 +20,7 @@ import Box from '@mui/material/Box'
|
|
|
20
20
|
import {Close} from 'mdi-material-ui'
|
|
21
21
|
import {useEffect, useState} from 'react'
|
|
22
22
|
import {useForm} from 'react-hook-form'
|
|
23
|
-
import {
|
|
23
|
+
import {Endpoints, Services} from 'src/services/Endpoints'
|
|
24
24
|
|
|
25
25
|
// ** Third Party Imports
|
|
26
26
|
|