izen-react-starter 2.3.7 → 2.4.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 CHANGED
@@ -681,6 +681,127 @@ export function UsersPage() {
681
681
  ```
682
682
  > **Tip:** You only need to set the baseURL once per app session. After that, all requests will use this base URL automatically. The token will always be injected from AuthProvider for every request.
683
683
 
684
+ #### Refresh token endpoint (optional)
685
+
686
+ If your backend uses a refresh endpoint, set it alongside the base URL so auth-aware hooks can reuse it:
687
+
688
+ ```tsx
689
+ import { useEffect } from 'react';
690
+ import { useApiService } from 'izen-react-starter';
691
+
692
+ function App() {
693
+ const apiService = useApiService();
694
+
695
+ useEffect(() => {
696
+ apiService.setBaseURL('https://api.example.com');
697
+ apiService.setRefreshTokenUrl('/auth/refresh');
698
+ }, [apiService]);
699
+
700
+ return <YourApp />;
701
+ }
702
+ ```
703
+
704
+ ### Auth Axios hook (useAxiosAuth)
705
+
706
+ `useAxiosAuth` returns an axios instance with auth interceptors and automatic token refresh. It uses the `baseURL` and optional refresh URL you set on `apiService`.
707
+
708
+ ```tsx
709
+ import { useEffect } from 'react';
710
+ import { useApiService } from 'izen-react-starter';
711
+ import { useAxiosAuth } from 'izen-react-starter';
712
+
713
+ function Profile() {
714
+ const apiService = useApiService();
715
+
716
+ // Ensure base URL (and refresh URL if needed) are set once
717
+ useEffect(() => {
718
+ apiService.setBaseURL('https://api.example.com');
719
+ apiService.setRefreshTokenUrl('/auth/refresh');
720
+ }, [apiService]);
721
+
722
+ const axiosAuth = useAxiosAuth();
723
+
724
+ const loadProfile = async () => {
725
+ const res = await axiosAuth.get('/me');
726
+ return res.data;
727
+ };
728
+
729
+ // ...use loadProfile inside effects or react-query
730
+ return null;
731
+ }
732
+ ```
733
+
734
+ ### Generic queries (useGet / useGetSingle)
735
+
736
+ React Query wrappers that reuse the auth axios instance. Make sure `apiService` has a base URL set before calling them.
737
+
738
+ ```tsx
739
+ import { useEffect } from 'react';
740
+ import { useApiService, useGet, useGetSingle } from 'izen-react-starter';
741
+
742
+ function UsersScreen() {
743
+ const apiService = useApiService();
744
+
745
+ useEffect(() => {
746
+ apiService.setBaseURL('https://api.example.com');
747
+ }, [apiService]);
748
+
749
+ const usersQuery = useGet<{ id: string; name: string }>('/users');
750
+ const userQuery = useGetSingle<{ id: string; name: string }>(`/users/${usersQuery.data?.[0]?.id}`, undefined, undefined, '/users/1');
751
+
752
+ if (usersQuery.isLoading) return <div>Loading users...</div>;
753
+ if (usersQuery.error) return <div>Error: {String(usersQuery.error)}</div>;
754
+
755
+ return (
756
+ <div>
757
+ {usersQuery.data?.map((u) => (
758
+ <div key={u.id}>{u.name}</div>
759
+ ))}
760
+ <div>User detail: {userQuery.data?.name}</div>
761
+ </div>
762
+ );
763
+ }
764
+ ```
765
+
766
+ ### Utility helpers (payload, time, HTML)
767
+
768
+ These utilities are exported from `izen-react-starter/lib`:
769
+
770
+ - `formatPayloadForEndpoint` (alias: `formatAxiosData`) — normalize payloads per endpoint (e.g., multipart for file-heavy routes, boolean fixes, role permissions, employee shifts).
771
+ - `buildMultipartFormData`, `buildRolePermissionsFormData`, `buildEmployeeShiftFormData` — helpers used by `formatPayloadForEndpoint` that you can also call directly.
772
+ - `removeHtmlTags` — strip HTML tags from strings.
773
+ - Time helpers: `parseTimeToMilliseconds`, `diffHoursFromTimestamps` (alias: `TimeDiffHours`), `subtractTimeStrings`, `sumTimeStrings`, `formatSecondsToHms` (aliases: `secondsToTime`, `formatTimeStr`).
774
+ - Date helpers: `toUTCDateString`/`toUTCDateTimeString`, `getWeekRange` (alias: `getWeekBounds`).
775
+
776
+ Example payload formatting:
777
+
778
+ ```ts
779
+ import { formatPayloadForEndpoint } from 'izen-react-starter/lib';
780
+
781
+ // Multipart for file upload endpoints
782
+ const payload = { name: 'Test', image: myFile };
783
+ const body = formatPayloadForEndpoint(payload, '/lessons');
784
+ await axios.post('/lessons', body);
785
+
786
+ // Role permissions (only true values become permissions[])
787
+ const roleBody = formatPayloadForEndpoint({ name: 'admin', manage_users: true }, '/roles');
788
+ await axios.post('/roles', roleBody);
789
+
790
+ // Employee shifts schedule
791
+ const shiftBody = formatPayloadForEndpoint({ employeeShifts: { mon: { start: '09:00', end: '17:00' } } }, '/employee-shifts/schedule-update');
792
+ await axios.post('/employee-shifts/schedule-update', shiftBody);
793
+ ```
794
+
795
+ Example time helpers:
796
+
797
+ ```ts
798
+ import { parseTimeToMilliseconds, subtractTimeStrings, formatSecondsToHms } from 'izen-react-starter/lib';
799
+
800
+ const ms = parseTimeToMilliseconds('09:30'); // 34200000
801
+ const diff = subtractTimeStrings('10:30', '09:00'); // "01:30:00"
802
+ const pretty = formatSecondsToHms(3661); // "01:01:01"
803
+ ```
804
+
684
805
  ### Role-Based Access Control (RBAC)
685
806
 
686
807
  The RBAC system is now fully configurable! Define your own roles, resources, and rules.
@@ -1,5 +1,5 @@
1
- import { c as s, T as c, P as u, a as i, b as m, C as P, Q as d } from "./AP7HFJJL-uVnY5RPz.js";
2
- import { g as h, c as v, a as e } from "./index-BWKXTVrJ.js";
1
+ import { c as s, T as c, P as u, a as i, b as m, C as P, Q as d } from "./AP7HFJJL-B_liWFpt.js";
2
+ import { g as h, c as v, a as e } from "./index-Gs1Xd6jo.js";
3
3
  var C = (r) => {
4
4
  const [t, o] = s({
5
5
  prefix: "TanstackQueryDevtools"
@@ -1,7 +1,7 @@
1
1
  var xs = Object.defineProperty;
2
2
  var $s = (e, t, n) => t in e ? xs(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n;
3
3
  var Re = (e, t, n) => $s(e, typeof t != "symbol" ? t + "" : t, n);
4
- import { b as $e, d as B, o as ft, e as H, c as P, a as m, P as No, m as ve, S as K, t as _, i as k, f as U, h as F, j as Cs, k as ur, u as Ce, l as V, s as Qn, n as Yn, p as gt, q as T, r as Ss, v as Ut, w as _t, x as qe, y as ks, z as Rt, A as Bt, B as Es, C as Ds, D as En, F as As, E as Ht, $ as Ho, G as Ms, H as Ts, I as W, J as Vr, K as Fs, L as Is, M as cr, N as Os, O as Ls, Q as Hn, R as Ps, T as qs, U as ie, V as _s, W as Rs } from "./index-BWKXTVrJ.js";
4
+ import { b as $e, d as B, o as ft, e as H, c as P, a as m, P as No, m as ve, S as K, t as _, i as k, f as U, h as F, j as Cs, k as ur, u as Ce, l as V, s as Qn, n as Yn, p as gt, q as T, r as Ss, v as Ut, w as _t, x as qe, y as ks, z as Rt, A as Bt, B as Es, C as Ds, D as En, F as As, E as Ht, $ as Ho, G as Ms, H as Ts, I as W, J as Vr, K as Fs, L as Is, M as cr, N as Os, O as Ls, Q as Hn, R as Ps, T as qs, U as ie, V as _s, W as Rs } from "./index-Gs1Xd6jo.js";
5
5
  var zs = (e) => e != null, Ks = (e) => e.filter(zs);
6
6
  function Bs(e) {
7
7
  return (...t) => {
@@ -1,5 +1,5 @@
1
- import { c, T as l, P as m, a as u, D as v, Q as i } from "./AP7HFJJL-uVnY5RPz.js";
2
- import { g as d, c as f, a as e } from "./index-BWKXTVrJ.js";
1
+ import { c, T as l, P as m, a as u, D as v, Q as i } from "./AP7HFJJL-B_liWFpt.js";
2
+ import { g as d, c as f, a as e } from "./index-Gs1Xd6jo.js";
3
3
  var h = (t) => {
4
4
  const [r, o] = c({
5
5
  prefix: "TanstackQueryDevtools"
@@ -1,4 +1,3 @@
1
- import { AxiosInstance } from 'axios';
2
1
  import { z } from 'zod';
3
2
  export interface FormLayoutProps<TFieldValues extends Record<string, any> = Record<string, any>> {
4
3
  item?: Partial<TFieldValues>;
@@ -17,7 +16,6 @@ export interface FormLayoutProps<TFieldValues extends Record<string, any> = Reco
17
16
  dataFormatter?: Partial<Record<keyof TFieldValues | string, (data: any) => unknown>>;
18
17
  baseURL?: string;
19
18
  multipartUrls?: string[];
20
- axiosInstance?: AxiosInstance;
21
19
  }
22
- export default function FormLayout<TFieldValues extends Record<string, any> = Record<string, any>>({ item, url, redirectUrl, edit, showCancelBtn, showNewBtn, onSave, onReset, onError, children, resetForm, validationSchema, requestHeaders, dataFormatter, baseURL, multipartUrls, axiosInstance, }: FormLayoutProps<TFieldValues>): import("react/jsx-runtime").JSX.Element;
20
+ export default function FormLayout<TFieldValues extends Record<string, any> = Record<string, any>>({ item, url, redirectUrl, edit, showCancelBtn, showNewBtn, onSave, onReset, onError, children, resetForm, validationSchema, requestHeaders, dataFormatter, baseURL, multipartUrls, }: FormLayoutProps<TFieldValues>): import("react/jsx-runtime").JSX.Element;
23
21
  //# sourceMappingURL=FormLayout.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FormLayout.d.ts","sourceRoot":"","sources":["../../../src/components/form/FormLayout.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAsB,MAAM,OAAO,CAAC;AAG1D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAiBxB,MAAM,WAAW,eAAe,CAAC,YAAY,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAC7F,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,GAAG,MAAM,KAAK,IAAI,CAAC;IACnD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC3C,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,aAAa,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAoCD,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,YAAY,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EACjG,IAAI,EACJ,GAAG,EACH,WAAW,EACX,IAAW,EACX,aAAqB,EACrB,UAAiB,EACjB,MAAM,EACN,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,OAAY,EACZ,aAAkB,EAClB,aAAa,GACd,EAAE,eAAe,CAAC,YAAY,CAAC,2CA4K/B"}
1
+ {"version":3,"file":"FormLayout.d.ts","sourceRoot":"","sources":["../../../src/components/form/FormLayout.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAgBxB,MAAM,WAAW,eAAe,CAAC,YAAY,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;IAC7F,IAAI,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,GAAG,MAAM,KAAK,IAAI,CAAC;IACnD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAC3C,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,aAAa,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC;IACrF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAoCD,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,YAAY,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,EACjG,IAAI,EACJ,GAAG,EACH,WAAW,EACX,IAAW,EACX,aAAqB,EACrB,UAAiB,EACjB,MAAM,EACN,OAAO,EACP,OAAO,EACP,QAAQ,EACR,SAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,OAAY,EACZ,aAAkB,GACjB,EAAE,eAAe,CAAC,YAAY,CAAC,2CAyKjC"}
@@ -16,5 +16,5 @@ export interface FileUploadProps {
16
16
  axiosInstance?: AxiosInstance;
17
17
  mapResponseToAttachment?: (response: any, file: File) => Attachment;
18
18
  }
19
- export default function FileUpload({ title, name, uploadUrl, downloadBaseUrl, accept, headers, baseURL, axiosInstance, mapResponseToAttachment, }: FileUploadProps): import("react/jsx-runtime").JSX.Element;
19
+ export default function FileUpload({ title, name, uploadUrl, downloadBaseUrl, accept, headers, baseURL, mapResponseToAttachment, }: FileUploadProps): import("react/jsx-runtime").JSX.Element;
20
20
  //# sourceMappingURL=FileUpload.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FileUpload.d.ts","sourceRoot":"","sources":["../../../../src/components/form/inputs/FileUpload.tsx"],"names":[],"mappings":"AACA,OAAO,EAAe,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAsB,MAAM,OAAO,CAAC;AAU1D,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,uBAAuB,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,KAAK,UAAU,CAAC;CACrE;AAMD,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,EACjC,KAAK,EACL,IAAI,EACJ,SAAS,EACT,eAAe,EACf,MAAsB,EACtB,OAAO,EACP,OAAY,EACZ,aAAa,EACb,uBAAuB,GACxB,EAAE,eAAe,2CA+LjB"}
1
+ {"version":3,"file":"FileUpload.d.ts","sourceRoot":"","sources":["../../../../src/components/form/inputs/FileUpload.tsx"],"names":[],"mappings":"AACA,OAAO,EAAe,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAsB,MAAM,OAAO,CAAC;AAS1D,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,uBAAuB,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,KAAK,UAAU,CAAC;CACrE;AAMD,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,EACjC,KAAK,EACL,IAAI,EACJ,SAAS,EACT,eAAe,EACf,MAAsB,EACtB,OAAO,EACP,OAAY,EACZ,uBAAuB,GACxB,EAAE,eAAe,2CA4LjB"}