@c-rex/templates 0.1.28 → 0.1.30

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/src/home/page.tsx CHANGED
@@ -1,377 +1,377 @@
1
- "use client";
2
-
3
- import React, { FC, useEffect, useMemo, useState } from "react";
4
- import { Funnel, Settings2, X } from "lucide-react"
5
- import { useTranslations } from 'next-intl'
6
- import { parseAsBoolean, parseAsInteger, parseAsString, useQueryStates } from 'nuqs'
7
- import { informationUnitsResponse } from "@c-rex/interfaces";
8
- import { Button } from "@c-rex/ui/button";
9
- import { Badge } from "@c-rex/ui/badge";
10
- import { ResultContainer } from "@c-rex/components/result-container";
11
- import { DialogFilter } from "@c-rex/components/dialog-filter";
12
- import { AutoComplete } from "@c-rex/components/autocomplete";
13
- import { DEVICE_OPTIONS, OPERATOR_OPTIONS } from "@c-rex/constants";
14
- import { FilterSidebar } from "./components/filter-sidebar";
15
- import { Sheet } from "@c-rex/ui/sheet";
16
- import { useBreakpoint } from "@c-rex/ui/hooks";
17
- import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@c-rex/ui/tooltip";
18
-
19
- interface HomePageProps {
20
- data: informationUnitsResponse;
21
- }
22
-
23
- type filterModel = {
24
- key: string
25
- name?: string
26
- value: string
27
- default?: string | boolean | null
28
- removable: boolean
29
- }
30
-
31
- type TagsType = {
32
- [key: string]: any[]
33
- }
34
-
35
- export const HomePage: FC<HomePageProps> = ({ data }) => {
36
- const t = useTranslations();
37
- const device = useBreakpoint();
38
- const isMobile = device !== null && device === DEVICE_OPTIONS.MOBILE;
39
- const [open, setOpen] = useState<boolean>(false)
40
- const [params, setParams] = useQueryStates({
41
- language: parseAsString,
42
- page: parseAsInteger,
43
- wildcard: parseAsString,
44
- operator: parseAsString,
45
- packages: parseAsString,
46
- filter: parseAsString,
47
- like: parseAsBoolean,
48
- search: {
49
- defaultValue: "",
50
- parse(value) {
51
- return value
52
- },
53
- },
54
- }, {
55
- history: 'push',
56
- shallow: false,
57
- });
58
-
59
- const tags: TagsType = useMemo(() => {
60
- if (!data) return {};
61
- const newTags = { ...data.tags }
62
-
63
- if (params.filter !== null) {
64
- const splittedParam = params.filter.split(",")
65
-
66
- splittedParam.forEach((item) => {
67
- const aux = item.split(".shortId=")
68
- const name = aux[0] as string
69
- const shortId = aux[1] as string
70
-
71
- if (!Object.keys(newTags).includes(name)) {
72
- newTags[name] = []
73
- }
74
-
75
- newTags[name].forEach((el: any) => {
76
- if (el.shortId == shortId) {
77
- el.active = true
78
- } else {
79
- el.active = false
80
- }
81
- })
82
- })
83
- } else {
84
- Object.keys(newTags).forEach((key) => {
85
- newTags[key].forEach((el: any) => {
86
- el.active = false
87
- })
88
- })
89
- }
90
-
91
- if (params.packages !== null && newTags["packages"]) {
92
- newTags["packages"].forEach((el: any) => {
93
- if (el.shortId == params.packages) {
94
- el.active = true
95
- } else {
96
- el.active = false
97
- }
98
- })
99
- }
100
-
101
- return newTags
102
- }, [data, params]);
103
-
104
- const filters = useMemo(() => {
105
- if (!tags || params.search.length === 0) return [];
106
-
107
- const filters: filterModel[] = [{
108
- key: "operator",
109
- name: t("filter.operator"),
110
- value: `${params?.operator !== OPERATOR_OPTIONS.OR}`,
111
- removable: false
112
- }, {
113
- key: "like",
114
- name: t("filter.like"),
115
- value: `${params.like}`,
116
- removable: false
117
- }, {
118
- key: "wildcard",
119
- name: "Wildcard",
120
- value: params.wildcard as string,
121
- removable: false,
122
- }]
123
-
124
- const languages = params.language?.split(",")
125
- languages?.forEach((item) => {
126
- const aux = languages?.filter(langItem => langItem !== item)
127
- filters.push({ key: "language", name: t(`languages`), value: item.toUpperCase(), removable: languages.length > 1, default: aux.join(",") })
128
- })
129
-
130
- if (params.filter !== null) {
131
- const splittedParam = params.filter.split(",")
132
-
133
- splittedParam.forEach((item, index) => {
134
- const aux = item.split(".shortId=")
135
- const name = aux[0] as string
136
- const shortId = aux[1] as string
137
-
138
- const defaultValue = [...splittedParam]
139
- defaultValue.splice(index, 1)
140
-
141
- if (!Object.keys(tags).includes(name) || !tags[name]) return;
142
-
143
- const tag = tags[name].find(el => el.shortId === shortId)
144
- if (!tag) return;
145
-
146
- const value = defaultValue.length == 0 ? null : defaultValue.join(",")
147
-
148
- filters.push({
149
- key: "filter",
150
- name: t(`filter.tags.${name}`),
151
- value: tag.label,
152
- removable: true,
153
- default: value
154
- })
155
- })
156
- }
157
-
158
- if (params.packages !== null) {
159
- let packageTag = {
160
- label: params.packages,
161
- }
162
-
163
- if (tags["packages"]) {
164
- packageTag = tags["packages"]?.find(el => el.shortId === params.packages)
165
- }
166
-
167
- filters.push({
168
- key: "packages",
169
- name: t("filter.tags.packages"),
170
- value: packageTag.label,
171
- removable: true,
172
- default: null
173
- })
174
- }
175
-
176
- Object.keys(params)
177
- .filter(item => !["page", "search", "language", "operator", "like", "wildcard", "filter", "packages"].includes(item))
178
- .forEach(item => {
179
- if (params[item as keyof typeof params] === null || params[item as keyof typeof params] === undefined) return;
180
- const value = params[item as keyof typeof params] as string
181
- filters.push({ key: item, value: value, removable: true, default: null })
182
- })
183
-
184
- return filters
185
- }, [tags, params]);
186
-
187
-
188
- const updateFilterParam = (key: string, item: any) => {
189
-
190
- if (item.active) {
191
- removeFilterItem(key, item)
192
- setOpen(false);
193
- return;
194
- }
195
-
196
- if (key === "packages") {
197
- setParams({ packages: item.shortId })
198
- return;
199
- }
200
-
201
- const value = `${key}.shortId=${item.shortId}`
202
- let aux = value
203
-
204
- if (params.filter != null) {
205
- const splittedParam = params.filter.split(",")
206
- const finalValue = [...splittedParam]
207
-
208
- const hasParams = params.filter.includes(key)
209
-
210
- if (hasParams) {
211
- let mainIndex = -1
212
-
213
- splittedParam.forEach((el, index) => {
214
- if (el.includes(key)) {
215
- mainIndex = index
216
- }
217
- })
218
- finalValue[mainIndex] = value
219
- } else {
220
- finalValue.push(value)
221
- }
222
-
223
- aux = finalValue.join(",")
224
- }
225
-
226
- setParams({ filter: aux })
227
- setOpen(false);
228
- };
229
-
230
- const removeFilterItem = (key: string, item: any) => {
231
- if (key === "packages") {
232
- setParams({ packages: null })
233
- return;
234
- }
235
-
236
- if (params.filter !== null) {
237
- const value = `${key}.shortId=${item.shortId}`
238
- const newValue = params.filter.split(",").filter(item => item !== value).join(",")
239
- setParams({ filter: newValue.length === 0 ? null : newValue })
240
- }
241
- }
242
-
243
- return (
244
- <div className="container">
245
- <div className="flex gap-4 py-6">
246
- <div className="flex-1">
247
- <AutoComplete
248
- embedded={false}
249
- initialValue={params.search}
250
- searchByPackage={false}
251
- />
252
- </div>
253
- <DialogFilter
254
- trigger={(
255
- <Button variant="default">
256
- <span className="hidden sm:inline">
257
- {t("searchSettings")}
258
- </span>
259
- <Settings2 />
260
- </Button>
261
- )}
262
- />
263
- </div>
264
-
265
- {filters != null && filters.length > 0 && (
266
- <div className="pb-4 flex justify-between">
267
-
268
- <div className="flex flex-wrap gap-2">
269
- <Button
270
- size="sm"
271
- variant="secondary"
272
- onClick={() => setOpen(true)}
273
- className="md:hidden"
274
- >
275
- <Funnel className="h-2" />
276
- </Button>
277
-
278
- {filters.length > 0 && (
279
- <>
280
- {filters.slice(0, 1).map((item) => (
281
- <Badge
282
- key={`${item.key}-${item?.value}`}
283
- variant="outline"
284
- className="h-8"
285
- >
286
- {item?.name ? item.name : item.key}: {item.value}
287
-
288
- {item.removable && (
289
- <Button size="xs" variant="ghost" onClick={() => {
290
- setParams({ [item.key]: item?.default })
291
- }}>
292
- <X className="h-2" />
293
- </Button>
294
- )}
295
- </Badge>
296
- ))}
297
-
298
- {isMobile ? (
299
- <TooltipProvider>
300
- <Tooltip delayDuration={100}>
301
- <TooltipTrigger>
302
- <Badge
303
- key={`grouped-filters`}
304
- variant="outline"
305
- className="h-8"
306
- >
307
- +{filters.length - 1} {t("filter.filters")}
308
- </Badge>
309
-
310
- </TooltipTrigger>
311
-
312
- <TooltipContent>
313
- {filters.slice(1).map((item) => {
314
- const label = item?.name ? item.name : item.key
315
- const returnString = `${label}: ${item.value}`;
316
- return <div className="capitalize" key={returnString}>{returnString}</div>;
317
- })}
318
- </TooltipContent>
319
- </Tooltip>
320
- </TooltipProvider>
321
- ) : (
322
- <>
323
- {filters.slice(1).map((item) => (
324
- <Badge
325
- key={`${item.key}-${item?.value}`}
326
- variant="outline"
327
- className="h-8"
328
- >
329
- {item?.name ? item.name : item.key}: {item.value}
330
-
331
- {item.removable && (
332
- <Button size="xs" variant="ghost" onClick={() => {
333
- setParams({ [item.key]: item?.default })
334
- }}>
335
- <X className="h-2" />
336
- </Button>
337
- )}
338
- </Badge>
339
- ))}
340
- </>
341
- )}
342
- </>
343
- )}
344
- </div>
345
-
346
- <Button
347
- size="sm"
348
- variant="secondary"
349
- onClick={() => {
350
- setParams({ filter: null, packages: null })
351
- }}
352
- >
353
- {t("reset")}
354
- </Button>
355
-
356
- </div>
357
- )}
358
-
359
- <div className="flex flex-row gap-6 pb-6">
360
- <Sheet open={open} onOpenChange={setOpen}>
361
- <FilterSidebar
362
- tags={tags}
363
- totalItemCount={data.pageInfo.totalItemCount}
364
- updateFilterParam={updateFilterParam}
365
- />
366
- </Sheet>
367
-
368
- <div className="flex-1">
369
- <ResultContainer
370
- items={data.items}
371
- pagination={data.pageInfo}
372
- />
373
- </div>
374
- </div>
375
- </div>
376
- );
1
+ "use client";
2
+
3
+ import React, { FC, useEffect, useMemo, useState } from "react";
4
+ import { Funnel, Settings2, X } from "lucide-react"
5
+ import { useTranslations } from 'next-intl'
6
+ import { parseAsBoolean, parseAsInteger, parseAsString, useQueryStates } from 'nuqs'
7
+ import { informationUnitsResponse } from "@c-rex/interfaces";
8
+ import { Button } from "@c-rex/ui/button";
9
+ import { Badge } from "@c-rex/ui/badge";
10
+ import { ResultContainer } from "@c-rex/components/result-container";
11
+ import { DialogFilter } from "@c-rex/components/dialog-filter";
12
+ import { AutoComplete } from "@c-rex/components/autocomplete";
13
+ import { DEVICE_OPTIONS, OPERATOR_OPTIONS } from "@c-rex/constants";
14
+ import { FilterSidebar } from "./components/filter-sidebar";
15
+ import { Sheet } from "@c-rex/ui/sheet";
16
+ import { useBreakpoint } from "@c-rex/ui/hooks";
17
+ import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@c-rex/ui/tooltip";
18
+
19
+ interface HomePageProps {
20
+ data: informationUnitsResponse;
21
+ }
22
+
23
+ type filterModel = {
24
+ key: string
25
+ name?: string
26
+ value: string
27
+ default?: string | boolean | null
28
+ removable: boolean
29
+ }
30
+
31
+ type TagsType = {
32
+ [key: string]: any[]
33
+ }
34
+
35
+ export const HomePage: FC<HomePageProps> = ({ data }) => {
36
+ const t = useTranslations();
37
+ const device = useBreakpoint();
38
+ const isMobile = device !== null && device === DEVICE_OPTIONS.MOBILE;
39
+ const [open, setOpen] = useState<boolean>(false)
40
+ const [params, setParams] = useQueryStates({
41
+ language: parseAsString,
42
+ page: parseAsInteger,
43
+ wildcard: parseAsString,
44
+ operator: parseAsString,
45
+ packages: parseAsString,
46
+ filter: parseAsString,
47
+ like: parseAsBoolean,
48
+ search: {
49
+ defaultValue: "",
50
+ parse(value) {
51
+ return value
52
+ },
53
+ },
54
+ }, {
55
+ history: 'push',
56
+ shallow: false,
57
+ });
58
+
59
+ const tags: TagsType = useMemo(() => {
60
+ if (!data) return {};
61
+ const newTags = { ...data.tags }
62
+
63
+ if (params.filter !== null) {
64
+ const splittedParam = params.filter.split(",")
65
+
66
+ splittedParam.forEach((item) => {
67
+ const aux = item.split(".shortId=")
68
+ const name = aux[0] as string
69
+ const shortId = aux[1] as string
70
+
71
+ if (!Object.keys(newTags).includes(name)) {
72
+ newTags[name] = []
73
+ }
74
+
75
+ newTags[name].forEach((el: any) => {
76
+ if (el.shortId == shortId) {
77
+ el.active = true
78
+ } else {
79
+ el.active = false
80
+ }
81
+ })
82
+ })
83
+ } else {
84
+ Object.keys(newTags).forEach((key) => {
85
+ newTags[key].forEach((el: any) => {
86
+ el.active = false
87
+ })
88
+ })
89
+ }
90
+
91
+ if (params.packages !== null && newTags["packages"]) {
92
+ newTags["packages"].forEach((el: any) => {
93
+ if (el.shortId == params.packages) {
94
+ el.active = true
95
+ } else {
96
+ el.active = false
97
+ }
98
+ })
99
+ }
100
+
101
+ return newTags
102
+ }, [data, params]);
103
+
104
+ const filters = useMemo(() => {
105
+ if (!tags || params.search.length === 0) return [];
106
+
107
+ const filters: filterModel[] = [{
108
+ key: "operator",
109
+ name: t("filter.operator"),
110
+ value: `${params?.operator !== OPERATOR_OPTIONS.OR}`,
111
+ removable: false
112
+ }, {
113
+ key: "like",
114
+ name: t("filter.like"),
115
+ value: `${params.like}`,
116
+ removable: false
117
+ }, {
118
+ key: "wildcard",
119
+ name: "Wildcard",
120
+ value: params.wildcard as string,
121
+ removable: false,
122
+ }]
123
+
124
+ const languages = params.language?.split(",")
125
+ languages?.forEach((item) => {
126
+ const aux = languages?.filter(langItem => langItem !== item)
127
+ filters.push({ key: "language", name: t(`languages`), value: item.toUpperCase(), removable: languages.length > 1, default: aux.join(",") })
128
+ })
129
+
130
+ if (params.filter !== null) {
131
+ const splittedParam = params.filter.split(",")
132
+
133
+ splittedParam.forEach((item, index) => {
134
+ const aux = item.split(".shortId=")
135
+ const name = aux[0] as string
136
+ const shortId = aux[1] as string
137
+
138
+ const defaultValue = [...splittedParam]
139
+ defaultValue.splice(index, 1)
140
+
141
+ if (!Object.keys(tags).includes(name) || !tags[name]) return;
142
+
143
+ const tag = tags[name].find(el => el.shortId === shortId)
144
+ if (!tag) return;
145
+
146
+ const value = defaultValue.length == 0 ? null : defaultValue.join(",")
147
+
148
+ filters.push({
149
+ key: "filter",
150
+ name: t(`filter.tags.${name}`),
151
+ value: tag.label,
152
+ removable: true,
153
+ default: value
154
+ })
155
+ })
156
+ }
157
+
158
+ if (params.packages !== null) {
159
+ let packageTag = {
160
+ label: params.packages,
161
+ }
162
+
163
+ if (tags["packages"]) {
164
+ packageTag = tags["packages"]?.find(el => el.shortId === params.packages)
165
+ }
166
+
167
+ filters.push({
168
+ key: "packages",
169
+ name: t("filter.tags.packages"),
170
+ value: packageTag.label,
171
+ removable: true,
172
+ default: null
173
+ })
174
+ }
175
+
176
+ Object.keys(params)
177
+ .filter(item => !["page", "search", "language", "operator", "like", "wildcard", "filter", "packages"].includes(item))
178
+ .forEach(item => {
179
+ if (params[item as keyof typeof params] === null || params[item as keyof typeof params] === undefined) return;
180
+ const value = params[item as keyof typeof params] as string
181
+ filters.push({ key: item, value: value, removable: true, default: null })
182
+ })
183
+
184
+ return filters
185
+ }, [tags, params]);
186
+
187
+
188
+ const updateFilterParam = (key: string, item: any) => {
189
+
190
+ if (item.active) {
191
+ removeFilterItem(key, item)
192
+ setOpen(false);
193
+ return;
194
+ }
195
+
196
+ if (key === "packages") {
197
+ setParams({ packages: item.shortId })
198
+ return;
199
+ }
200
+
201
+ const value = `${key}.shortId=${item.shortId}`
202
+ let aux = value
203
+
204
+ if (params.filter != null) {
205
+ const splittedParam = params.filter.split(",")
206
+ const finalValue = [...splittedParam]
207
+
208
+ const hasParams = params.filter.includes(key)
209
+
210
+ if (hasParams) {
211
+ let mainIndex = -1
212
+
213
+ splittedParam.forEach((el, index) => {
214
+ if (el.includes(key)) {
215
+ mainIndex = index
216
+ }
217
+ })
218
+ finalValue[mainIndex] = value
219
+ } else {
220
+ finalValue.push(value)
221
+ }
222
+
223
+ aux = finalValue.join(",")
224
+ }
225
+
226
+ setParams({ filter: aux })
227
+ setOpen(false);
228
+ };
229
+
230
+ const removeFilterItem = (key: string, item: any) => {
231
+ if (key === "packages") {
232
+ setParams({ packages: null })
233
+ return;
234
+ }
235
+
236
+ if (params.filter !== null) {
237
+ const value = `${key}.shortId=${item.shortId}`
238
+ const newValue = params.filter.split(",").filter(item => item !== value).join(",")
239
+ setParams({ filter: newValue.length === 0 ? null : newValue })
240
+ }
241
+ }
242
+
243
+ return (
244
+ <div className="container">
245
+ <div className="flex gap-4 py-6">
246
+ <div className="flex-1">
247
+ <AutoComplete
248
+ embedded={false}
249
+ initialValue={params.search}
250
+ searchByPackage={false}
251
+ />
252
+ </div>
253
+ <DialogFilter
254
+ trigger={(
255
+ <Button variant="default">
256
+ <span className="hidden sm:inline">
257
+ {t("searchSettings")}
258
+ </span>
259
+ <Settings2 />
260
+ </Button>
261
+ )}
262
+ />
263
+ </div>
264
+
265
+ {filters != null && filters.length > 0 && (
266
+ <div className="pb-4 flex justify-between">
267
+
268
+ <div className="flex flex-wrap gap-2">
269
+ <Button
270
+ size="sm"
271
+ variant="secondary"
272
+ onClick={() => setOpen(true)}
273
+ className="md:hidden"
274
+ >
275
+ <Funnel className="h-2" />
276
+ </Button>
277
+
278
+ {filters.length > 0 && (
279
+ <>
280
+ {filters.slice(0, 1).map((item) => (
281
+ <Badge
282
+ key={`${item.key}-${item?.value}`}
283
+ variant="outline"
284
+ className="h-8"
285
+ >
286
+ {item?.name ? item.name : item.key}: {item.value}
287
+
288
+ {item.removable && (
289
+ <Button size="xs" variant="ghost" onClick={() => {
290
+ setParams({ [item.key]: item?.default })
291
+ }}>
292
+ <X className="h-2" />
293
+ </Button>
294
+ )}
295
+ </Badge>
296
+ ))}
297
+
298
+ {isMobile ? (
299
+ <TooltipProvider>
300
+ <Tooltip delayDuration={100}>
301
+ <TooltipTrigger>
302
+ <Badge
303
+ key={`grouped-filters`}
304
+ variant="outline"
305
+ className="h-8"
306
+ >
307
+ +{filters.length - 1} {t("filter.filters")}
308
+ </Badge>
309
+
310
+ </TooltipTrigger>
311
+
312
+ <TooltipContent>
313
+ {filters.slice(1).map((item) => {
314
+ const label = item?.name ? item.name : item.key
315
+ const returnString = `${label}: ${item.value}`;
316
+ return <div className="capitalize" key={returnString}>{returnString}</div>;
317
+ })}
318
+ </TooltipContent>
319
+ </Tooltip>
320
+ </TooltipProvider>
321
+ ) : (
322
+ <>
323
+ {filters.slice(1).map((item) => (
324
+ <Badge
325
+ key={`${item.key}-${item?.value}`}
326
+ variant="outline"
327
+ className="h-8"
328
+ >
329
+ {item?.name ? item.name : item.key}: {item.value}
330
+
331
+ {item.removable && (
332
+ <Button size="xs" variant="ghost" onClick={() => {
333
+ setParams({ [item.key]: item?.default })
334
+ }}>
335
+ <X className="h-2" />
336
+ </Button>
337
+ )}
338
+ </Badge>
339
+ ))}
340
+ </>
341
+ )}
342
+ </>
343
+ )}
344
+ </div>
345
+
346
+ <Button
347
+ size="sm"
348
+ variant="secondary"
349
+ onClick={() => {
350
+ setParams({ filter: null, packages: null })
351
+ }}
352
+ >
353
+ {t("reset")}
354
+ </Button>
355
+
356
+ </div>
357
+ )}
358
+
359
+ <div className="flex flex-row gap-6 pb-6">
360
+ <Sheet open={open} onOpenChange={setOpen}>
361
+ <FilterSidebar
362
+ tags={tags}
363
+ totalItemCount={data.pageInfo.totalItemCount}
364
+ updateFilterParam={updateFilterParam}
365
+ />
366
+ </Sheet>
367
+
368
+ <div className="flex-1">
369
+ <ResultContainer
370
+ items={data.items}
371
+ pagination={data.pageInfo}
372
+ />
373
+ </div>
374
+ </div>
375
+ </div>
376
+ );
377
377
  };