mobigrid-module 1.0.1 → 1.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,157 +0,0 @@
1
- import * as React from "react"
2
- import * as SelectPrimitive from "@radix-ui/react-select"
3
- import { Check, ChevronDown, ChevronUp } from "lucide-react"
4
-
5
- import { cn } from "../../lib/utils"
6
-
7
- const Select = SelectPrimitive.Root
8
-
9
- const SelectGroup = SelectPrimitive.Group
10
-
11
- const SelectValue = SelectPrimitive.Value
12
-
13
- const SelectTrigger = React.forwardRef<
14
- React.ElementRef<typeof SelectPrimitive.Trigger>,
15
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
16
- >(({ className, children, ...props }, ref) => (
17
- <SelectPrimitive.Trigger
18
- ref={ref}
19
- className={cn(
20
- "flex h-9 w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
21
- className
22
- )}
23
- {...props}
24
- >
25
- {children}
26
- <SelectPrimitive.Icon asChild>
27
- <ChevronDown className="h-4 w-4 opacity-50" />
28
- </SelectPrimitive.Icon>
29
- </SelectPrimitive.Trigger>
30
- ))
31
- SelectTrigger.displayName = SelectPrimitive.Trigger.displayName
32
-
33
- const SelectScrollUpButton = React.forwardRef<
34
- React.ElementRef<typeof SelectPrimitive.ScrollUpButton>,
35
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollUpButton>
36
- >(({ className, ...props }, ref) => (
37
- <SelectPrimitive.ScrollUpButton
38
- ref={ref}
39
- className={cn(
40
- "flex cursor-default items-center justify-center py-1",
41
- className
42
- )}
43
- {...props}
44
- >
45
- <ChevronUp className="h-4 w-4" />
46
- </SelectPrimitive.ScrollUpButton>
47
- ))
48
- SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName
49
-
50
- const SelectScrollDownButton = React.forwardRef<
51
- React.ElementRef<typeof SelectPrimitive.ScrollDownButton>,
52
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.ScrollDownButton>
53
- >(({ className, ...props }, ref) => (
54
- <SelectPrimitive.ScrollDownButton
55
- ref={ref}
56
- className={cn(
57
- "flex cursor-default items-center justify-center py-1",
58
- className
59
- )}
60
- {...props}
61
- >
62
- <ChevronDown className="h-4 w-4" />
63
- </SelectPrimitive.ScrollDownButton>
64
- ))
65
- SelectScrollDownButton.displayName =
66
- SelectPrimitive.ScrollDownButton.displayName
67
-
68
- const SelectContent = React.forwardRef<
69
- React.ElementRef<typeof SelectPrimitive.Content>,
70
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
71
- >(({ className, children, position = "popper", ...props }, ref) => (
72
- <SelectPrimitive.Portal>
73
- <SelectPrimitive.Content
74
- ref={ref}
75
- className={cn(
76
- "relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
77
- position === "popper" &&
78
- "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
79
- className
80
- )}
81
- position={position}
82
- {...props}
83
- >
84
- <SelectScrollUpButton />
85
- <SelectPrimitive.Viewport
86
- className={cn(
87
- "p-1",
88
- position === "popper" &&
89
- "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
90
- )}
91
- >
92
- {children}
93
- </SelectPrimitive.Viewport>
94
- <SelectScrollDownButton />
95
- </SelectPrimitive.Content>
96
- </SelectPrimitive.Portal>
97
- ))
98
- SelectContent.displayName = SelectPrimitive.Content.displayName
99
-
100
- const SelectLabel = React.forwardRef<
101
- React.ElementRef<typeof SelectPrimitive.Label>,
102
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
103
- >(({ className, ...props }, ref) => (
104
- <SelectPrimitive.Label
105
- ref={ref}
106
- className={cn("px-2 py-1.5 text-sm font-semibold", className)}
107
- {...props}
108
- />
109
- ))
110
- SelectLabel.displayName = SelectPrimitive.Label.displayName
111
-
112
- const SelectItem = React.forwardRef<
113
- React.ElementRef<typeof SelectPrimitive.Item>,
114
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
115
- >(({ className, children, ...props }, ref) => (
116
- <SelectPrimitive.Item
117
- ref={ref}
118
- className={cn(
119
- "relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
120
- className
121
- )}
122
- {...props}
123
- >
124
- <span className="absolute right-2 flex h-3.5 w-3.5 items-center justify-center">
125
- <SelectPrimitive.ItemIndicator>
126
- <Check className="h-4 w-4" />
127
- </SelectPrimitive.ItemIndicator>
128
- </span>
129
- <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
130
- </SelectPrimitive.Item>
131
- ))
132
- SelectItem.displayName = SelectPrimitive.Item.displayName
133
-
134
- const SelectSeparator = React.forwardRef<
135
- React.ElementRef<typeof SelectPrimitive.Separator>,
136
- React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
137
- >(({ className, ...props }, ref) => (
138
- <SelectPrimitive.Separator
139
- ref={ref}
140
- className={cn("-mx-1 my-1 h-px bg-muted", className)}
141
- {...props}
142
- />
143
- ))
144
- SelectSeparator.displayName = SelectPrimitive.Separator.displayName
145
-
146
- export {
147
- Select,
148
- SelectGroup,
149
- SelectValue,
150
- SelectTrigger,
151
- SelectContent,
152
- SelectLabel,
153
- SelectItem,
154
- SelectSeparator,
155
- SelectScrollUpButton,
156
- SelectScrollDownButton,
157
- }
@@ -1,30 +0,0 @@
1
- import React from "react"
2
- import { useTheme } from "next-themes"
3
- import { Toaster as Sonner } from "sonner"
4
-
5
- type ToasterProps = React.ComponentProps<typeof Sonner>
6
-
7
- const Toaster = ({ ...props }: ToasterProps) => {
8
- const { theme = "system" } = useTheme()
9
-
10
- return (
11
- <Sonner
12
- theme={theme as ToasterProps["theme"]}
13
- className="toaster group"
14
- toastOptions={{
15
- classNames: {
16
- toast:
17
- "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
18
- description: "group-[.toast]:text-muted-foreground",
19
- actionButton:
20
- "group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
21
- cancelButton:
22
- "group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
23
- },
24
- }}
25
- {...props}
26
- />
27
- )
28
- }
29
-
30
- export { Toaster }
@@ -1,120 +0,0 @@
1
- import * as React from "react"
2
-
3
- import { cn } from "../../lib/utils"
4
-
5
- const Table = React.forwardRef<
6
- HTMLTableElement,
7
- React.HTMLAttributes<HTMLTableElement>
8
- >(({ className, ...props }, ref) => (
9
- <div className="relative w-full overflow-auto">
10
- <table
11
- ref={ref}
12
- className={cn("w-full caption-bottom text-sm", className)}
13
- {...props}
14
- />
15
- </div>
16
- ))
17
- Table.displayName = "Table"
18
-
19
- const TableHeader = React.forwardRef<
20
- HTMLTableSectionElement,
21
- React.HTMLAttributes<HTMLTableSectionElement>
22
- >(({ className, ...props }, ref) => (
23
- <thead ref={ref} className={cn("[&_tr]:border-b", className)} {...props} />
24
- ))
25
- TableHeader.displayName = "TableHeader"
26
-
27
- const TableBody = React.forwardRef<
28
- HTMLTableSectionElement,
29
- React.HTMLAttributes<HTMLTableSectionElement>
30
- >(({ className, ...props }, ref) => (
31
- <tbody
32
- ref={ref}
33
- className={cn("[&_tr:last-child]:border-0", className)}
34
- {...props}
35
- />
36
- ))
37
- TableBody.displayName = "TableBody"
38
-
39
- const TableFooter = React.forwardRef<
40
- HTMLTableSectionElement,
41
- React.HTMLAttributes<HTMLTableSectionElement>
42
- >(({ className, ...props }, ref) => (
43
- <tfoot
44
- ref={ref}
45
- className={cn(
46
- "border-t bg-muted/50 font-medium [&>tr]:last:border-b-0",
47
- className
48
- )}
49
- {...props}
50
- />
51
- ))
52
- TableFooter.displayName = "TableFooter"
53
-
54
- const TableRow = React.forwardRef<
55
- HTMLTableRowElement,
56
- React.HTMLAttributes<HTMLTableRowElement>
57
- >(({ className, ...props }, ref) => (
58
- <tr
59
- ref={ref}
60
- className={cn(
61
- "border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted",
62
- className
63
- )}
64
- {...props}
65
- />
66
- ))
67
- TableRow.displayName = "TableRow"
68
-
69
- const TableHead = React.forwardRef<
70
- HTMLTableCellElement,
71
- React.ThHTMLAttributes<HTMLTableCellElement>
72
- >(({ className, ...props }, ref) => (
73
- <th
74
- ref={ref}
75
- className={cn(
76
- "h-10 px-2 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
77
- className
78
- )}
79
- {...props}
80
- />
81
- ))
82
- TableHead.displayName = "TableHead"
83
-
84
- const TableCell = React.forwardRef<
85
- HTMLTableCellElement,
86
- React.TdHTMLAttributes<HTMLTableCellElement>
87
- >(({ className, ...props }, ref) => (
88
- <td
89
- ref={ref}
90
- className={cn(
91
- "p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]",
92
- className
93
- )}
94
- {...props}
95
- />
96
- ))
97
- TableCell.displayName = "TableCell"
98
-
99
- const TableCaption = React.forwardRef<
100
- HTMLTableCaptionElement,
101
- React.HTMLAttributes<HTMLTableCaptionElement>
102
- >(({ className, ...props }, ref) => (
103
- <caption
104
- ref={ref}
105
- className={cn("mt-4 text-sm text-muted-foreground", className)}
106
- {...props}
107
- />
108
- ))
109
- TableCaption.displayName = "TableCaption"
110
-
111
- export {
112
- Table,
113
- TableHeader,
114
- TableBody,
115
- TableFooter,
116
- TableHead,
117
- TableRow,
118
- TableCell,
119
- TableCaption,
120
- }
package/src/index.tsx DELETED
@@ -1,254 +0,0 @@
1
- import React from "react";
2
- import { useEffect, useState } from "react";
3
- import { format } from "date-fns";
4
- import axios from "axios";
5
- import { Alert, AlertTitle, AlertDescription } from "./components/ui/alert";
6
- import { AlertCircle } from "lucide-react";
7
- import { PageHeader } from "./components/Layout/PageHeader";
8
- import { CustomTable } from "./components/CustomTable/CustomTable";
9
- import Pagination from "./components/CustomTable/Pagination";
10
-
11
- const ITEMS_PER_PAGE = 14;
12
-
13
- interface ContainerProps {
14
- configUrl: string;
15
- preJsUrl: string;
16
- itemsPerPage?: number;
17
- children?: React.ReactNode;
18
- }
19
-
20
- const MobigridModule = ({
21
- configUrl,
22
- preJsUrl,
23
- itemsPerPage = ITEMS_PER_PAGE,
24
- children,
25
- }: ContainerProps) {
26
- const [config, setConfig] = useState<any>(null);
27
- const [invalidConfig, setInvalidConfig] = useState(false);
28
- const [errors, setErrors] = useState<
29
- Array<{
30
- title: string;
31
- message: string;
32
- }>
33
- >([]);
34
- const [isLoading, setIsLoading] = useState(false);
35
- const [data, setData] = useState([]);
36
- const [count, setCount] = useState(0);
37
- const [currentPage, setCurrentPage] = useState(1);
38
- const [totalPages, setTotalPages] = useState(1);
39
- const [filters, setFilters] = useState({
40
- fromDate: new Date(
41
- new Date().getFullYear(),
42
- new Date().getMonth(),
43
- 1
44
- ).toLocaleString(),
45
- toDate: new Date(
46
- new Date().getFullYear(),
47
- new Date().getMonth() + 1,
48
- 0,
49
- 23,
50
- 59,
51
- 59
52
- ).toLocaleString(),
53
- });
54
- const [filterOptions, setFilterOptions] = useState<any[]>([]);
55
-
56
- useEffect(() => {
57
- const loadConfig = async () => {
58
- try {
59
- const response = await fetch(configUrl);
60
- const data = await response.json();
61
- if (data && data.title && data.data_url && data.colomns) {
62
- setConfig(data);
63
- setFilterOptions(data.Filters?.flat() || []);
64
- } else {
65
- setInvalidConfig(true);
66
- }
67
- } catch (error) {
68
- setInvalidConfig(true);
69
- }
70
- };
71
-
72
- const loadFunctions = async () => {
73
- const response = await fetch(preJsUrl);
74
- const script = document.createElement("script");
75
- script.textContent = await response.text();
76
- document.head.appendChild(script);
77
- };
78
-
79
- if (configUrl && preJsUrl) {
80
- loadConfig();
81
- loadFunctions();
82
- }
83
- }, [configUrl, preJsUrl]);
84
-
85
- useEffect(() => {
86
- const controller = new AbortController();
87
-
88
- const initializeFilters = async () => {
89
- const filters = config?.Filters?.flat() || [];
90
- for (const filter of filters) {
91
- if (filter.type === "Select" && filter.urlSource) {
92
- await fetchFilterOptions(filter, controller.signal);
93
- }
94
- }
95
- };
96
-
97
- if (config) initializeFilters();
98
-
99
- return () => controller.abort();
100
- }, [config]);
101
-
102
- const getData = async () => {
103
- setErrors([]);
104
- const postBody = {
105
- page: currentPage,
106
- filters: {
107
- ...filters,
108
- fromDate: format(filters.fromDate, "MM-dd-yyyy HH:mm"),
109
- toDate: format(filters.toDate, "MM-dd-yyyy HH:mm"),
110
- },
111
- };
112
-
113
- setIsLoading(true);
114
- try {
115
- const response = await axios.post(config.data_url, postBody);
116
- setIsLoading(false);
117
-
118
- if (response?.data) {
119
- setData(response.data?.DATA);
120
- setCount(response.data?.PAGESNUM);
121
- setTotalPages(Math.ceil(response.data?.PAGESNUM / itemsPerPage) || 1);
122
- } else {
123
- setInvalidConfig(true);
124
- }
125
- } catch (error) {
126
- setIsLoading(false);
127
- setErrors((prev) => [
128
- ...prev,
129
- {
130
- title: "Erreur",
131
- message: "Une erreur est survenue",
132
- },
133
- ]);
134
- }
135
- };
136
-
137
- const fetchFilterOptions = async (filter: any, signal?: AbortSignal) => {
138
- if (filter.type === "Select" && filter.urlSource) {
139
- try {
140
- const response = await axios.get(filter.urlSource, { signal });
141
- if (response?.status === 200 && response?.data) {
142
- const options = Array.isArray(response.data) ? response.data : [];
143
- setFilterOptions((prev) =>
144
- prev.map((f) => (f.name === filter.name ? { ...f, options } : f))
145
- );
146
- }
147
- } catch (error) {
148
- if (!axios.isCancel(error)) {
149
- setErrors((prev) => [
150
- ...prev,
151
- {
152
- title: "Erreur",
153
- message: `Une erreur est survenue lors de la récupération des options pour ${filter.name}`,
154
- },
155
- ]);
156
- console.error(`Error fetching options for ${filter.name}:`, error);
157
- }
158
- }
159
- }
160
- };
161
-
162
- if (invalidConfig) {
163
- return (
164
- <div
165
- style={{
166
- display: "flex",
167
- justifyContent: "center",
168
- alignItems: "center",
169
- height: "100vh",
170
- }}
171
- >
172
- <div style={{ position: "absolute" }}>
173
- <svg
174
- className="h-5 w-5 mx-auto mb-2"
175
- xmlns="http://www.w3.org/2000/svg"
176
- viewBox="0 0 24 24"
177
- fill="red"
178
- >
179
- <path d="M18.3 5.71a.996.996 0 00-1.41 0L12 10.59 7.11 5.7A.996.996 0 105.7 7.11L10.59 12 5.7 16.89a.996.996 0 101.41 1.41L12 13.41l4.89 4.89a.996.996 0 101.41-1.41L13.41 12l4.89-4.89c.38-.38.38-1.02 0-1.4z" />
180
- </svg>
181
- <div>Invalid configuration</div>
182
- </div>
183
- </div>
184
- );
185
- }
186
-
187
- if (!config) {
188
- return (
189
- <div
190
- style={{
191
- display: "flex",
192
- justifyContent: "center",
193
- alignItems: "center",
194
- height: "100vh",
195
- }}
196
- >
197
- <div style={{ position: "absolute" }}>
198
- <svg
199
- className="animate-spin h-5 w-5 mx-auto mb-2"
200
- xmlns="http://www.w3.org/2000/svg"
201
- fill="none"
202
- viewBox="0 0 24 24"
203
- >
204
- <circle
205
- className="opacity-25"
206
- cx="12"
207
- cy="12"
208
- r="10"
209
- stroke="currentColor"
210
- strokeWidth="4"
211
- ></circle>
212
- <path
213
- className="opacity-75"
214
- fill="currentColor"
215
- d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
216
- ></path>
217
- </svg>
218
- <div>Loading configuration...</div>
219
- </div>
220
- </div>
221
- );
222
- }
223
-
224
- return (
225
- <div className="flex flex-col gap-4 p-4 max-w-[1300px] mx-auto mt-8 mb-">
226
- <PageHeader
227
- title={config.title}
228
- configFilters={filterOptions}
229
- filters={filters}
230
- setFilters={setFilters}
231
- onSearch={() => getData()}
232
- count={count}
233
- isLoading={isLoading}
234
- setCurrentPage={setCurrentPage}
235
- />
236
- {errors.map((error, index) => (
237
- <Alert key={index} variant="destructive">
238
- <AlertCircle className="h-4 w-4" />
239
- <AlertTitle>{error.title}</AlertTitle>
240
- <AlertDescription>{error.message}</AlertDescription>
241
- </Alert>
242
- ))}
243
- <CustomTable data={data} columns={config.colomns} isLoading={isLoading} />
244
- <Pagination
245
- currentPage={currentPage}
246
- totalPages={totalPages}
247
- onPageChange={setCurrentPage}
248
- />
249
- {children}
250
- </div>
251
- );
252
- }
253
-
254
- export default MobigridModule;
package/src/lib/utils.ts DELETED
@@ -1,6 +0,0 @@
1
- import { type ClassValue, clsx } from "clsx"
2
- import { twMerge } from "tailwind-merge"
3
-
4
- export function cn(...inputs: ClassValue[]) {
5
- return twMerge(clsx(inputs))
6
- }
package/tsconfig.json DELETED
@@ -1,27 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES5",
4
- "module": "ESNext",
5
- "declaration": true,
6
- "declarationDir": "dist/types",
7
- "outDir": "dist",
8
- "jsx": "react",
9
- "strict": true,
10
- "esModuleInterop": true,
11
- "skipLibCheck": true,
12
- "moduleResolution": "node",
13
- "baseUrl": "./",
14
- "paths": {
15
- "*": [
16
- "node_modules/*"
17
- ]
18
- }
19
- },
20
- "include": [
21
- "src/**/*"
22
- ],
23
- "exclude": [
24
- "node_modules",
25
- "dist"
26
- ]
27
- }
package/vite.config.ts DELETED
@@ -1,6 +0,0 @@
1
- import { defineConfig } from 'vite'
2
- import react from '@vitejs/plugin-react'
3
-
4
- export default defineConfig({
5
- plugins: [react()],
6
- })