@airoom/nextmin-react 0.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.
Files changed (95) hide show
  1. package/LICENSE +49 -0
  2. package/README.md +133 -0
  3. package/dist/auth/AuthPage.d.ts +1 -0
  4. package/dist/auth/AuthPage.js +23 -0
  5. package/dist/auth/ForgotPasswordForm.d.ts +1 -0
  6. package/dist/auth/ForgotPasswordForm.js +28 -0
  7. package/dist/auth/SignInForm.d.ts +6 -0
  8. package/dist/auth/SignInForm.js +38 -0
  9. package/dist/auth/SignUpForm.d.ts +3 -0
  10. package/dist/auth/SignUpForm.js +30 -0
  11. package/dist/components/AddressAutocomplete.d.ts +21 -0
  12. package/dist/components/AddressAutocomplete.js +182 -0
  13. package/dist/components/AdminApp.d.ts +1 -0
  14. package/dist/components/AdminApp.js +134 -0
  15. package/dist/components/ConfirmDialog.d.ts +12 -0
  16. package/dist/components/ConfirmDialog.js +6 -0
  17. package/dist/components/FileUploader.d.ts +32 -0
  18. package/dist/components/FileUploader.js +480 -0
  19. package/dist/components/NoAccess.d.ts +3 -0
  20. package/dist/components/NoAccess.js +5 -0
  21. package/dist/components/PasswordInput.d.ts +19 -0
  22. package/dist/components/PasswordInput.js +11 -0
  23. package/dist/components/PhoneInput.d.ts +23 -0
  24. package/dist/components/PhoneInput.js +147 -0
  25. package/dist/components/RefMultiSelect.d.ts +14 -0
  26. package/dist/components/RefMultiSelect.js +76 -0
  27. package/dist/components/RefSingleSelect.d.ts +17 -0
  28. package/dist/components/RefSingleSelect.js +52 -0
  29. package/dist/components/SchemaForm.d.ts +13 -0
  30. package/dist/components/SchemaForm.js +592 -0
  31. package/dist/components/SectionLoader.d.ts +3 -0
  32. package/dist/components/SectionLoader.js +7 -0
  33. package/dist/components/Sidebar.d.ts +1 -0
  34. package/dist/components/Sidebar.js +87 -0
  35. package/dist/components/TableFilters.d.ts +16 -0
  36. package/dist/components/TableFilters.js +69 -0
  37. package/dist/components/TableSkeleton.d.ts +7 -0
  38. package/dist/components/TableSkeleton.js +5 -0
  39. package/dist/hooks/useGoogleMapsKey.d.ts +5 -0
  40. package/dist/hooks/useGoogleMapsKey.js +16 -0
  41. package/dist/index.d.ts +2 -0
  42. package/dist/index.js +2 -0
  43. package/dist/lib/api.d.ts +31 -0
  44. package/dist/lib/api.js +94 -0
  45. package/dist/lib/auth.d.ts +23 -0
  46. package/dist/lib/auth.js +51 -0
  47. package/dist/lib/googleLoader.d.ts +1 -0
  48. package/dist/lib/googleLoader.js +25 -0
  49. package/dist/lib/schemaService.d.ts +2 -0
  50. package/dist/lib/schemaService.js +39 -0
  51. package/dist/lib/schemaUtils.d.ts +4 -0
  52. package/dist/lib/schemaUtils.js +18 -0
  53. package/dist/lib/types.d.ts +50 -0
  54. package/dist/lib/types.js +1 -0
  55. package/dist/nextmin.css +1 -0
  56. package/dist/providers/NextMinProvider.d.ts +5 -0
  57. package/dist/providers/NextMinProvider.js +30 -0
  58. package/dist/router/AdminRouteNormalizer.d.ts +1 -0
  59. package/dist/router/AdminRouteNormalizer.js +32 -0
  60. package/dist/router/NextMinRouter.d.ts +1 -0
  61. package/dist/router/NextMinRouter.js +99 -0
  62. package/dist/state/nextMinSlice.d.ts +14 -0
  63. package/dist/state/nextMinSlice.js +34 -0
  64. package/dist/state/schemaLive.d.ts +2 -0
  65. package/dist/state/schemaLive.js +19 -0
  66. package/dist/state/schemasSlice.d.ts +20 -0
  67. package/dist/state/schemasSlice.js +43 -0
  68. package/dist/state/sessionSlice.d.ts +10 -0
  69. package/dist/state/sessionSlice.js +18 -0
  70. package/dist/state/store.d.ts +28 -0
  71. package/dist/state/store.js +7 -0
  72. package/dist/views/CreateEditPage.d.ts +4 -0
  73. package/dist/views/CreateEditPage.js +64 -0
  74. package/dist/views/DashboardPage.d.ts +1 -0
  75. package/dist/views/DashboardPage.js +107 -0
  76. package/dist/views/ListPage.d.ts +5 -0
  77. package/dist/views/ListPage.js +76 -0
  78. package/dist/views/NextNotFound.d.ts +1 -0
  79. package/dist/views/NextNotFound.js +6 -0
  80. package/dist/views/ProfilePage.d.ts +1 -0
  81. package/dist/views/ProfilePage.js +193 -0
  82. package/dist/views/SettingsEdit.d.ts +2 -0
  83. package/dist/views/SettingsEdit.js +87 -0
  84. package/dist/views/list/DataTableHero.d.ts +22 -0
  85. package/dist/views/list/DataTableHero.js +350 -0
  86. package/dist/views/list/ListHeader.d.ts +8 -0
  87. package/dist/views/list/ListHeader.js +7 -0
  88. package/dist/views/list/Pagination.d.ts +8 -0
  89. package/dist/views/list/Pagination.js +5 -0
  90. package/dist/views/list/formatters.d.ts +2 -0
  91. package/dist/views/list/formatters.js +62 -0
  92. package/dist/views/list/useListData.d.ts +10 -0
  93. package/dist/views/list/useListData.js +79 -0
  94. package/package.json +51 -0
  95. package/tsconfig.json +18 -0
@@ -0,0 +1,7 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import Link from 'next/link';
4
+ import { Button, Divider } from '@heroui/react';
5
+ export function ListHeader({ title, createHref, hideCreate = false, loading, }) {
6
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [_jsx("h2", { className: "m-0 text-xl font-semibold", children: title }), _jsx("div", { className: "flex items-center gap-3", children: !hideCreate && (_jsx(Link, { href: createHref, children: _jsx(Button, { size: "sm", color: "primary", isDisabled: loading, children: "Create" }) })) })] }), _jsx(Divider, { className: "my-3" })] }));
7
+ }
@@ -0,0 +1,8 @@
1
+ type Props = {
2
+ page: number;
3
+ pageCount: number;
4
+ onPrev: () => void;
5
+ onNext: () => void;
6
+ };
7
+ export declare function Pagination({ page, pageCount, onPrev, onNext }: Props): import("react/jsx-runtime").JSX.Element;
8
+ export {};
@@ -0,0 +1,5 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ export function Pagination({ page, pageCount, onPrev, onNext }) {
4
+ return (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("button", { onClick: onPrev, disabled: page === 0, children: "Prev" }), _jsxs("span", { children: ["Page ", page + 1, " / ", pageCount] }), _jsx("button", { onClick: onNext, disabled: page + 1 >= pageCount, children: "Next" })] }));
5
+ }
@@ -0,0 +1,2 @@
1
+ export declare function formatAtom(v: any): string;
2
+ export declare function formatCell(val: any, key?: string): string;
@@ -0,0 +1,62 @@
1
+ function isCreatedOrUpdated(key) {
2
+ const k = (key || '').toLowerCase().replace(/[^a-z]/g, '');
3
+ return k === 'createdat' || k === 'updatedat';
4
+ }
5
+ function tryParseDate(val) {
6
+ if (val == null)
7
+ return null;
8
+ // Handle numeric timestamps (ms or s)
9
+ if (typeof val === 'number') {
10
+ const ms = val < 1e11 ? val * 1000 : val; // heuristic: 10/13-digit
11
+ const d = new Date(ms);
12
+ return isNaN(d.getTime()) ? null : d;
13
+ }
14
+ // ISO string / Date
15
+ const d = new Date(val);
16
+ return isNaN(d.getTime()) ? null : d;
17
+ }
18
+ function formatLongDate(d) {
19
+ const day = d.getDate(); // no leading zero: "1 August, 2025"
20
+ const month = d.toLocaleString('en', { month: 'long' });
21
+ const year = d.getFullYear();
22
+ return `${day} ${month}, ${year}`; // "13 August, 2025"
23
+ }
24
+ export function formatAtom(v) {
25
+ if (v == null)
26
+ return '';
27
+ if (typeof v === 'string')
28
+ return v;
29
+ if (typeof v === 'number' || typeof v === 'boolean')
30
+ return String(v);
31
+ if (v && typeof v === 'object') {
32
+ // Common cases: show human-friendly fields if present
33
+ if (typeof v.name === 'string')
34
+ return v.name;
35
+ if (typeof v.title === 'string')
36
+ return v.title;
37
+ if (typeof v.id === 'string')
38
+ return v.id;
39
+ try {
40
+ return JSON.stringify(v);
41
+ }
42
+ catch {
43
+ return String(v);
44
+ }
45
+ }
46
+ return String(v);
47
+ }
48
+ export function formatCell(val, key) {
49
+ if (val == null)
50
+ return '';
51
+ // Only format dates for createdAt / updatedAt columns
52
+ if (isCreatedOrUpdated(key)) {
53
+ const d = tryParseDate(val);
54
+ if (d)
55
+ return formatLongDate(d);
56
+ }
57
+ if (Array.isArray(val))
58
+ return val.map(formatAtom).join(', ');
59
+ if (typeof val === 'object')
60
+ return formatAtom(val);
61
+ return String(val);
62
+ }
@@ -0,0 +1,10 @@
1
+ import { type ListParams } from '../../lib/api';
2
+ export type ListState<T = unknown> = {
3
+ rows: T[];
4
+ total: number;
5
+ loading: boolean;
6
+ forbidden: boolean;
7
+ err: string | null;
8
+ };
9
+ export declare function useListData<T = unknown>(model: string, page: number, // 1-based
10
+ pageSize: number, filters?: ListParams): [ListState<T>, () => Promise<void>];
@@ -0,0 +1,79 @@
1
+ 'use client';
2
+ import { useCallback, useEffect, useRef, useState } from 'react';
3
+ import { api, ApiError } from '../../lib/api';
4
+ export function useListData(model, page, // 1-based
5
+ pageSize, filters = {}) {
6
+ const [state, setState] = useState({
7
+ rows: [],
8
+ total: 0,
9
+ loading: true,
10
+ forbidden: false,
11
+ err: null,
12
+ });
13
+ const cancelledRef = useRef(false);
14
+ const filtersKey = JSON.stringify(filters);
15
+ const load = useCallback(async () => {
16
+ setState((s) => ({ ...s, loading: true, forbidden: false, err: null }));
17
+ try {
18
+ const res = await api.list(model, Math.max(0, page - 1), pageSize, filters);
19
+ if (cancelledRef.current)
20
+ return;
21
+ // Support both {data, pagination} and {rows, total}
22
+ const rows = res?.data ??
23
+ (Array.isArray(res?.rows) ? res.rows : []) ??
24
+ [];
25
+ const totalServer = res?.pagination?.totalRows ??
26
+ (typeof res?.total === 'number'
27
+ ? res.total
28
+ : undefined);
29
+ const total = typeof totalServer === 'number'
30
+ ? totalServer
31
+ : Array.isArray(rows)
32
+ ? rows.length
33
+ : 0;
34
+ setState({
35
+ rows: Array.isArray(rows) ? rows : [],
36
+ total,
37
+ loading: false,
38
+ forbidden: false,
39
+ err: null,
40
+ });
41
+ }
42
+ catch (e) {
43
+ if (cancelledRef.current)
44
+ return;
45
+ if (e instanceof ApiError && (e.status === 401 || e.status === 403)) {
46
+ setState({
47
+ rows: [],
48
+ total: 0,
49
+ loading: false,
50
+ forbidden: true,
51
+ err: e.message ||
52
+ (e.status === 401 ? 'Not authenticated' : 'Not permitted'),
53
+ });
54
+ }
55
+ else {
56
+ const msg = e?.message?.toString() ??
57
+ 'Failed to load data';
58
+ setState({
59
+ rows: [],
60
+ total: 0,
61
+ loading: false,
62
+ forbidden: false,
63
+ err: msg,
64
+ });
65
+ }
66
+ }
67
+ }, [model, page, pageSize, filtersKey]);
68
+ useEffect(() => {
69
+ cancelledRef.current = false;
70
+ void load();
71
+ return () => {
72
+ cancelledRef.current = true;
73
+ };
74
+ }, [load]);
75
+ const refetch = useCallback(async () => {
76
+ await load();
77
+ }, [load]);
78
+ return [state, refetch];
79
+ }
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@airoom/nextmin-react",
3
+ "version": "0.1.0",
4
+ "license": "SEE LICENSE IN LICENSE",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
+ },
14
+ "./styles.css": "./dist/nextmin.css"
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "package.json",
19
+ "tsconfig.json",
20
+ "LICENSE",
21
+ "README.md"
22
+ ],
23
+ "scripts": {
24
+ "build": "rm -rf dist && tsc -p tsconfig.json && npm run build:css",
25
+ "build:css": "tailwindcss -c tailwind.config.js -i ./src/styles.css -o ./dist/nextmin.css --minify",
26
+ "dev": "tsc -w -p tsconfig.json",
27
+ "prepublishOnly": "npm run build && npm pack --dry-run | (! grep -E '\\bsrc/|\\.map$')"
28
+ },
29
+ "dependencies": {
30
+ "@googlemaps/js-api-loader": "^1.16.10",
31
+ "@heroui/react": "^2.8.2",
32
+ "@heroui/use-infinite-scroll": "^2.2.10",
33
+ "@internationalized/date": "^3.9.0",
34
+ "@reduxjs/toolkit": "^2.8.2",
35
+ "framer-motion": "^12.23.12",
36
+ "react": "*",
37
+ "react-dom": "*",
38
+ "react-redux": ">=9",
39
+ "socket.io-client": "^4.7.5"
40
+ },
41
+ "devDependencies": {
42
+ "@types/google.maps": "^3.58.1",
43
+ "autoprefixer": "^10.4.21",
44
+ "postcss": "^8.5.6",
45
+ "tailwindcss": "^3.4.17"
46
+ },
47
+ "sideEffects": false,
48
+ "publishConfig": {
49
+ "access": "public"
50
+ }
51
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,18 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "target": "ES2020",
5
+ "types": ["google.maps", "node"],
6
+ "module": "ESNext",
7
+ "moduleResolution": "Bundler",
8
+ "jsx": "react-jsx",
9
+ "declaration": true,
10
+ "outDir": "dist",
11
+ "rootDir": "src",
12
+ "esModuleInterop": true,
13
+ "skipLibCheck": true,
14
+ "resolveJsonModule": true,
15
+ "sourceMap": false
16
+ },
17
+ "include": ["src"]
18
+ }