@timum/timum_pdk 2.0.8 → 2.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.
@@ -0,0 +1,365 @@
1
+ import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
2
+
3
+ import failsaveStorage from "./util/failSafeLocalStorage";
4
+
5
+ let host = undefined;
6
+ export const setTimumApiHost = (url) => {
7
+ host = url;
8
+ };
9
+
10
+ export const getTimumApiHost = () => {
11
+ if (host) {
12
+ return host;
13
+ } else {
14
+ return failsaveStorage.get("timumApiHost", "https://www.timum.de");
15
+ }
16
+ };
17
+
18
+ // we do it this way so that the base url can be determined dynamically
19
+ export const getBaseUrl = () => {
20
+ return getTimumApiHost() + "/rest/1";
21
+ };
22
+
23
+ export const constructUrl = (url, props, plain) => {
24
+ if (props.params) {
25
+ for (const [paramName, paramValue] of Object.entries(props.params)) {
26
+ if (Array.isArray(paramValue)) {
27
+ for (let el of paramValue) {
28
+ if (!url.includes("?")) {
29
+ url = `${url}?${paramName}=${el}`;
30
+ } else {
31
+ url = `${url}&${paramName}=${el}`;
32
+ }
33
+ }
34
+
35
+ } else {
36
+ if (!url.includes("?")) {
37
+ url = `${url}?${paramName}=${paramValue}`;
38
+ } else {
39
+ url = `${url}&${paramName}=${paramValue}`;
40
+ }
41
+ }
42
+ }
43
+ }
44
+
45
+ if (!url.includes("?")) {
46
+ url = `${url}?X-DISABLE-COOKIES=true`;
47
+ } else {
48
+ url = `${url}&X-DISABLE-COOKIES=true`;
49
+ }
50
+
51
+ if (plain) {
52
+ return `${getTimumApiHost()}${url}`;
53
+ } else {
54
+ return `${getBaseUrl()}${url}`;
55
+ }
56
+ };
57
+
58
+ export const timumApiSlice = createApi({
59
+ reducerPath: "timumApi",
60
+ baseQuery: fetchBaseQuery({
61
+ baseUrl: undefined,
62
+ credentials: "include",
63
+ }),
64
+ tagTypes: [
65
+ "Timeslot",
66
+ "Product",
67
+ "Account",
68
+ "Provider",
69
+ "User",
70
+ "IdentifiedCustomer",
71
+ ],
72
+ endpoints: (builder) => ({
73
+ // ##########################################
74
+ // # ConsumerAPI v2
75
+ // ##########################################
76
+
77
+ upcomingBookables: builder.query({
78
+ query: (props) => ({
79
+ url: constructUrl(
80
+ `/resources/${props.channelOrResourceId}/upcoming_bookables`,
81
+ props
82
+ ),
83
+ headers: props.headers,
84
+ }),
85
+ providesTags: (/* result = [], error, arg */) => ["Timeslot"],
86
+ }),
87
+
88
+ specificBookables: builder.query({
89
+ query: (props) => ({
90
+ url: constructUrl(
91
+ `/bookables/specific_bookables`,
92
+ props
93
+ ),
94
+ headers: props.headers,
95
+ method: "post",
96
+ body: props.body,
97
+ }),
98
+ providesTags: (/* result = [], error, arg */) => ["Timeslot"],
99
+ }),
100
+
101
+ activeProducts: builder.query({
102
+ query: (props) => ({
103
+ url: constructUrl(
104
+ `/resources/${props.channelOrResourceId}/active_products`,
105
+ props
106
+ ),
107
+ headers: props.headers,
108
+ }),
109
+ providesTags: (/* result = [], error, arg */) => ["Product"],
110
+ }),
111
+
112
+
113
+
114
+ createAppointmentWithConsumer: builder.mutation({
115
+ query: (props) => ({
116
+ url: constructUrl(
117
+ `/resources/${props.channelOrResourceId}/create_appointment_with_consumer`,
118
+ props
119
+ ),
120
+ method: "post",
121
+ body: props.body,
122
+ headers: props.headers,
123
+ }),
124
+ invalidatesTags: (result, error, arg) => {
125
+ const invalidatedTags = [{ type: "Timeslot" }];
126
+
127
+ if (arg.shouldInvalidateCustomerIdentification) {
128
+ invalidatedTags.push({ type: "IdentifiedCustomer" });
129
+ }
130
+
131
+ return invalidatedTags;
132
+ },
133
+ }),
134
+
135
+ removeCustomerFromAppointment: builder.mutation({
136
+ query: (props) => ({
137
+ url: constructUrl(
138
+ `/customers/${props.customersId}/appointments/${props.appointmentId}`,
139
+ props
140
+ ),
141
+ method: "delete",
142
+ headers: props.headers,
143
+ }),
144
+ invalidatesTags: (/* result, error, arg */) => [{ type: "Timeslot" }],
145
+ }),
146
+
147
+ authenticate: builder.query({
148
+ query: (props) => {
149
+ return {
150
+ url: constructUrl(`/auth/cookieless/login`, props, true),
151
+ headers: props.headers,
152
+ method: "post",
153
+ body: props.body,
154
+ };
155
+ },
156
+ }),
157
+
158
+ /**
159
+ * Returns an object with the following makeup:
160
+ * {
161
+ * contact: {
162
+ * name,
163
+ * email,
164
+ * mobile,
165
+ * phone
166
+ * },
167
+ * resource: {
168
+ * name,
169
+ * description,
170
+ * msgHelpText
171
+ * },
172
+ * provider: {
173
+ * name
174
+ * }
175
+ * }
176
+ */
177
+ publicData: builder.query({
178
+ query: (props) => ({
179
+ url: constructUrl(
180
+ `/resources/${props.channelOrResourceId}/public_data`,
181
+ props
182
+ ),
183
+ headers: props.headers,
184
+ }),
185
+ }),
186
+
187
+ identifyCustomer: builder.query({
188
+ query: (props) => ({
189
+ url: constructUrl(
190
+ `/crms/${props.crmSlug}/resources/${props.channelOrResourceId}/customers/${props.personId}/identify`,
191
+ props
192
+ ),
193
+ headers: props.headers,
194
+ }),
195
+ providesTags: "IdentifiedCustomer", //
196
+ keepUnusedDataFor: 9999999, // once identified it's not going to change
197
+ }),
198
+
199
+ /**
200
+ * body contain:
201
+ * resource_id*,
202
+ * product_id*,
203
+ * provider_id,
204
+ * timeslotUuid (if available)
205
+ * from* (ISO format),
206
+ * to* (ISO format)
207
+ * -> * marks those which are required.
208
+ */
209
+ reserveAppoinment: builder.mutation({
210
+ query: (props) => ({
211
+ url: constructUrl(
212
+ `/resources/${props.channelOrResourceId}/reserve_appointment`,
213
+ props
214
+ ),
215
+ method: "post",
216
+ body: props.body,
217
+ headers: props.headers,
218
+ }),
219
+ }),
220
+
221
+ /**
222
+ * body must contain:
223
+ * placeholder_id (id created for ephemeral customer during call to),
224
+ * appointment_id
225
+ */
226
+ revokeAppointmentReservation: builder.mutation({
227
+ query: (props) => ({
228
+ url: constructUrl(
229
+ `/resources/${props.channelOrResourceId}/revoke_reservation`,
230
+ props
231
+ ),
232
+ method: "post",
233
+ body: props.body,
234
+ headers: props.headers,
235
+ }),
236
+ }),
237
+
238
+ // ##########################################
239
+ // # CRM API requests (general api)
240
+ // ##########################################
241
+
242
+ getAccount: builder.query({
243
+ query: (props) => ({
244
+ url: constructUrl(
245
+ `/crms/${props.platform}/account/${props.accountReference}`,
246
+ props
247
+ ),
248
+ }),
249
+ providesTags: (/* result = [], error, arg */) => ["Account"],
250
+ }),
251
+
252
+ createAccount: builder.mutation({
253
+ query: (props) => {
254
+ return {
255
+ url: constructUrl(`/crms/${props.platform}/account`, props),
256
+ method: "post",
257
+ body: JSON.stringify(props.accountData),
258
+ };
259
+ },
260
+ invalidatesTags: (/* result, error, arg */) => [{ type: "Account" }],
261
+ }),
262
+
263
+ getProviders: builder.query({
264
+ query: (props) => ({
265
+ url: constructUrl(
266
+ `/crms/${props.platform}/account/${props.accountReference}/providers`,
267
+ props
268
+ ),
269
+ }),
270
+ providesTags: (/* result = [], error, arg */) => ["Product"],
271
+ }),
272
+
273
+ getProvider: builder.query({
274
+ query: (props) => ({
275
+ url: constructUrl(
276
+ `/crms/${props.platform}/provider/${props.providerReference}`,
277
+ props
278
+ ),
279
+ }),
280
+ }),
281
+
282
+ createProvider: builder.mutation({
283
+ query: (props) => ({
284
+ url: constructUrl(`/crms/${props.platform}/provider`, props),
285
+ method: "post",
286
+ body: JSON.stringify(
287
+ (() => ({
288
+ user: props.userData ?? {},
289
+ provider: props.providerData ?? {},
290
+ address: props.addressData ?? null,
291
+ account: props.account ?? null,
292
+ sendEmail: props.sendEmail ?? false,
293
+ }))()
294
+ ),
295
+ }),
296
+ invalidatesTags: (/* result, error, arg */) => [{ type: "Provider" }],
297
+ }),
298
+
299
+ // loginUserViaApi: builder.query({
300
+ // query: (props) => ({
301
+ // url: constructUrl(`/crms/${props.platform}/user/loginWithJwt`),
302
+ // }),
303
+ // async onQueryStarted(props, { dispatch, queryFulfilled }) {
304
+ // const { data /* , meta */ } = await queryFulfilled;
305
+ // if (data) {
306
+ // dispatch(timumClientAuthorised({ auth2: data.auth2 }));
307
+ // }
308
+ // },
309
+ // }),
310
+ getUser: builder.query({
311
+ query: (props) => ({
312
+ url: constructUrl(
313
+ `/crms/${props.platform}/user/${props.userReference}`,
314
+ props
315
+ ),
316
+ }),
317
+ }),
318
+
319
+ createUser: builder.mutation({
320
+ query: (props) => ({
321
+ url: constructUrl(`/crms/${props.platform}/user`, props),
322
+ method: "post",
323
+ body: JSON.stringify(props.userData),
324
+ }),
325
+ invalidatesTags: (/* result, error, arg */) => [{ type: "User" }],
326
+ }),
327
+ }),
328
+ });
329
+
330
+ export const {
331
+ // ##########################################
332
+ // # ConsumerAPI v2
333
+ // ##########################################
334
+
335
+ useUpcomingBookablesQuery,
336
+ useLazyUpcomingBookablesQuery,
337
+ useSpecificBookablesQuery,
338
+ useLazySpecificBookablesQuery,
339
+ useActiveProductsQuery,
340
+ useLazyActiveProductsQuery,
341
+ useCreateAppointmentWithConsumerMutation,
342
+ useIdentifyCustomerQuery,
343
+ useLazyIdentifyCustomerQuery,
344
+ usePublicDataQuery,
345
+ useLazyPublicDataQuery,
346
+ useReserveAppoinmentMutation,
347
+ useRevokeAppointmentReservationMutation,
348
+ useRemoveCustomerFromAppointmentMutation,
349
+ useAuthenticateQuery,
350
+ useLazyAuthenticateQuery,
351
+
352
+ // ##########################################
353
+ // # CRM API requests (general api)
354
+ // ##########################################
355
+ useCreateAccountMutation,
356
+ useGetAccountQuery,
357
+ useLazyGetAccountQuery,
358
+ useGetProvidersQuery,
359
+ useLazyGetProvidersQuery,
360
+ useCreateProviderMutation,
361
+ // useLoginUserViaApiQuery,
362
+ useCreateUserMutation,
363
+ useGetUserQuery,
364
+ useLazyGetUserQuery,
365
+ } = timumApiSlice;
@@ -0,0 +1,50 @@
1
+ import { reactLocalStorage } from "reactjs-localstorage";
2
+
3
+ function get(key, defaultValue = undefined, silent = true) {
4
+ if (isLocalStorageAvailable()) {
5
+ return reactLocalStorage.get(key, defaultValue, silent);
6
+ } else {
7
+ return undefined;
8
+ }
9
+ }
10
+
11
+ function set(key, value) {
12
+ if (isLocalStorageAvailable()) {
13
+ reactLocalStorage.set(key, value);
14
+ }
15
+ }
16
+
17
+ function getObject(key, defaultValue = {}, silent = true) {
18
+ if (isLocalStorageAvailable()) {
19
+ return reactLocalStorage.getObject(key, defaultValue, silent);
20
+ } else {
21
+ return undefined;
22
+ }
23
+ }
24
+
25
+ function setObject(key, object) {
26
+ if (isLocalStorageAvailable()) {
27
+ return reactLocalStorage.setObject(key, object);
28
+ }
29
+ return undefined;
30
+ }
31
+
32
+ function isLocalStorageAvailable() {
33
+ var test = "test";
34
+ try {
35
+ localStorage.setItem(test, test);
36
+ localStorage.removeItem(test);
37
+ return true;
38
+ } catch (e) {
39
+ return false;
40
+ }
41
+ }
42
+
43
+ const failsaveStorage = {
44
+ get,
45
+ set,
46
+ getObject,
47
+ setObject,
48
+ };
49
+
50
+ export default failsaveStorage;