@redacto.io/consent-sdk-react 4.0.0 → 5.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 (161) hide show
  1. package/CHANGELOG.md +19 -1
  2. package/LICENSE +176 -0
  3. package/README.md +98 -1
  4. package/dist/index.js +231 -96
  5. package/dist/index.mjs +231 -96
  6. package/dist/privacy-center.d.mts +649 -0
  7. package/dist/privacy-center.d.ts +649 -0
  8. package/dist/privacy-center.js +20824 -0
  9. package/dist/privacy-center.mjs +20789 -0
  10. package/package.json +47 -3
  11. package/src/RedactoNoticeConsent/RedactoNoticeConsent.tsx +6 -4
  12. package/src/RedactoNoticeConsent/api/index.ts +2 -0
  13. package/src/RedactoNoticeConsent/api/types.ts +2 -0
  14. package/src/RedactoNoticeConsent/components/DigiLockerCallback.tsx +128 -62
  15. package/src/RedactoNoticeConsent/language-codes.ts +97 -0
  16. package/src/RedactoNoticeConsentInline/RedactoNoticeConsentInline.tsx +0 -3
  17. package/src/RedactoNoticeConsentInline/api/index.ts +0 -1
  18. package/src/RedactoPrivacyCenter/PrivacyCenterActivityPage.tsx +19 -0
  19. package/src/RedactoPrivacyCenter/PrivacyCenterCaseDetailsPage.tsx +154 -0
  20. package/src/RedactoPrivacyCenter/PrivacyCenterConsentManagerPage.tsx +17 -0
  21. package/src/RedactoPrivacyCenter/PrivacyCenterFormPage.tsx +79 -0
  22. package/src/RedactoPrivacyCenter/PrivacyCenterHomePage.tsx +30 -0
  23. package/src/RedactoPrivacyCenter/PrivacyCenterLayout.tsx +173 -0
  24. package/src/RedactoPrivacyCenter/RedactoPrivacyCenter.tsx +55 -0
  25. package/src/RedactoPrivacyCenter/api/actions.ts +476 -0
  26. package/src/RedactoPrivacyCenter/api/client.ts +524 -0
  27. package/src/RedactoPrivacyCenter/api/config.ts +33 -0
  28. package/src/RedactoPrivacyCenter/api/fetcher.ts +181 -0
  29. package/src/RedactoPrivacyCenter/api/upload.ts +93 -0
  30. package/src/RedactoPrivacyCenter/assets/character.svg +31 -0
  31. package/src/RedactoPrivacyCenter/assets/fileAttach.svg +9 -0
  32. package/src/RedactoPrivacyCenter/assets/greenTick.svg +4 -0
  33. package/src/RedactoPrivacyCenter/assets/mail.svg +3 -0
  34. package/src/RedactoPrivacyCenter/assets/poweredByRedacto.svg +9 -0
  35. package/src/RedactoPrivacyCenter/assets/sentImg.svg +9 -0
  36. package/src/RedactoPrivacyCenter/assets/uploadFileIcon.svg +9 -0
  37. package/src/RedactoPrivacyCenter/components/ActivitiesList.tsx +272 -0
  38. package/src/RedactoPrivacyCenter/components/CaseDetails/AttachmentCard.tsx +38 -0
  39. package/src/RedactoPrivacyCenter/components/CaseDetails/ChatBubble.tsx +31 -0
  40. package/src/RedactoPrivacyCenter/components/CaseDetails/DocumentRequestCard.tsx +73 -0
  41. package/src/RedactoPrivacyCenter/components/CaseDetails/MessageComposer.tsx +87 -0
  42. package/src/RedactoPrivacyCenter/components/CaseDetails/MessageItem.tsx +95 -0
  43. package/src/RedactoPrivacyCenter/components/CaseDetails/MessagesTab.tsx +147 -0
  44. package/src/RedactoPrivacyCenter/components/CaseDetails/RequestDetailsTab.tsx +171 -0
  45. package/src/RedactoPrivacyCenter/components/CaseDetails/StatusEvent.tsx +23 -0
  46. package/src/RedactoPrivacyCenter/components/CaseDetails/useFileUpload.ts +116 -0
  47. package/src/RedactoPrivacyCenter/components/CaseDetails/useMessagePolling.ts +36 -0
  48. package/src/RedactoPrivacyCenter/components/CaseDetails/utils.ts +56 -0
  49. package/src/RedactoPrivacyCenter/components/CaseDetailsModal.tsx +469 -0
  50. package/src/RedactoPrivacyCenter/components/CaseHistory.tsx +426 -0
  51. package/src/RedactoPrivacyCenter/components/ConsentManager.tsx +732 -0
  52. package/src/RedactoPrivacyCenter/components/ConsentManagerColumns.tsx +238 -0
  53. package/src/RedactoPrivacyCenter/components/ConsentManagerConstants.ts +7 -0
  54. package/src/RedactoPrivacyCenter/components/ConsentManagerTableSkeleton.tsx +155 -0
  55. package/src/RedactoPrivacyCenter/components/DataRequest/CorrectionDataSection.tsx +189 -0
  56. package/src/RedactoPrivacyCenter/components/DataRequest/GrievanceDataSection.tsx +118 -0
  57. package/src/RedactoPrivacyCenter/components/DataRequest/NominationDataSection.tsx +66 -0
  58. package/src/RedactoPrivacyCenter/components/DataRequest/PurposeSelectionSection.tsx +304 -0
  59. package/src/RedactoPrivacyCenter/components/Form.tsx +1596 -0
  60. package/src/RedactoPrivacyCenter/components/GrievanceTable.tsx +174 -0
  61. package/src/RedactoPrivacyCenter/components/GrievanceTablePagination.tsx +337 -0
  62. package/src/RedactoPrivacyCenter/components/ModifyConsentModal.tsx +330 -0
  63. package/src/RedactoPrivacyCenter/components/Pagination.tsx +140 -0
  64. package/src/RedactoPrivacyCenter/components/PrivacyCenterLayout.tsx +304 -0
  65. package/src/RedactoPrivacyCenter/components/RequestSubmit.tsx +232 -0
  66. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/SideBarPC.tsx +475 -0
  67. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/SideMenuPC.tsx +408 -0
  68. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/constants.tsx +42 -0
  69. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/menuItemsPC.tsx +1 -0
  70. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/types.ts +40 -0
  71. package/src/RedactoPrivacyCenter/components/SideMenuBarPC/utils.ts +38 -0
  72. package/src/RedactoPrivacyCenter/components/ThemeTransitionOverlay.tsx +85 -0
  73. package/src/RedactoPrivacyCenter/components/activitiesColumns.tsx +141 -0
  74. package/src/RedactoPrivacyCenter/components/caseHistoryColumns.tsx +159 -0
  75. package/src/RedactoPrivacyCenter/components/constant.ts +16 -0
  76. package/src/RedactoPrivacyCenter/components/types.ts +76 -0
  77. package/src/RedactoPrivacyCenter/components/utils.tsx +10 -0
  78. package/src/RedactoPrivacyCenter/config/routes.ts +9 -0
  79. package/src/RedactoPrivacyCenter/config/table.ts +25 -0
  80. package/src/RedactoPrivacyCenter/context/AuthContext.tsx +137 -0
  81. package/src/RedactoPrivacyCenter/context/BaseUrlContext.tsx +41 -0
  82. package/src/RedactoPrivacyCenter/context/LocaleContext.tsx +11 -0
  83. package/src/RedactoPrivacyCenter/context/NavigationContext.tsx +96 -0
  84. package/src/RedactoPrivacyCenter/context/OrganizationContext.tsx +30 -0
  85. package/src/RedactoPrivacyCenter/context/PageChromeContext.tsx +60 -0
  86. package/src/RedactoPrivacyCenter/context/theme.tsx +127 -0
  87. package/src/RedactoPrivacyCenter/context/types.ts +14 -0
  88. package/src/RedactoPrivacyCenter/lib/api.ts +566 -0
  89. package/src/RedactoPrivacyCenter/lib/consent-manager/utils.tsx +63 -0
  90. package/src/RedactoPrivacyCenter/lib/constants.ts +161 -0
  91. package/src/RedactoPrivacyCenter/lib/i18n.ts +81 -0
  92. package/src/RedactoPrivacyCenter/lib/locales.ts +105 -0
  93. package/src/RedactoPrivacyCenter/lib/queries.ts +134 -0
  94. package/src/RedactoPrivacyCenter/lib/types.ts +531 -0
  95. package/src/RedactoPrivacyCenter/lib/useCurrentLanguage.ts +37 -0
  96. package/src/RedactoPrivacyCenter/lib/utils.ts +626 -0
  97. package/src/RedactoPrivacyCenter/locales/as/translation.json +280 -0
  98. package/src/RedactoPrivacyCenter/locales/bho/translation.json +280 -0
  99. package/src/RedactoPrivacyCenter/locales/bn/translation.json +280 -0
  100. package/src/RedactoPrivacyCenter/locales/brx/translation.json +280 -0
  101. package/src/RedactoPrivacyCenter/locales/doi/translation.json +280 -0
  102. package/src/RedactoPrivacyCenter/locales/en/translation.json +255 -0
  103. package/src/RedactoPrivacyCenter/locales/gom/translation.json +280 -0
  104. package/src/RedactoPrivacyCenter/locales/gu/translation.json +280 -0
  105. package/src/RedactoPrivacyCenter/locales/hi/translation.json +280 -0
  106. package/src/RedactoPrivacyCenter/locales/kn/translation.json +280 -0
  107. package/src/RedactoPrivacyCenter/locales/ks/translation.json +280 -0
  108. package/src/RedactoPrivacyCenter/locales/mai/translation.json +280 -0
  109. package/src/RedactoPrivacyCenter/locales/ml/translation.json +280 -0
  110. package/src/RedactoPrivacyCenter/locales/mni-Mtei/translation.json +280 -0
  111. package/src/RedactoPrivacyCenter/locales/mr/translation.json +280 -0
  112. package/src/RedactoPrivacyCenter/locales/ne/translation.json +280 -0
  113. package/src/RedactoPrivacyCenter/locales/or/translation.json +280 -0
  114. package/src/RedactoPrivacyCenter/locales/pa/translation.json +280 -0
  115. package/src/RedactoPrivacyCenter/locales/sa/translation.json +280 -0
  116. package/src/RedactoPrivacyCenter/locales/sat/translation.json +280 -0
  117. package/src/RedactoPrivacyCenter/locales/sd/translation.json +280 -0
  118. package/src/RedactoPrivacyCenter/locales/ta/translation.json +280 -0
  119. package/src/RedactoPrivacyCenter/locales/te/translation.json +280 -0
  120. package/src/RedactoPrivacyCenter/locales/ur/translation.json +280 -0
  121. package/src/RedactoPrivacyCenter/styles/base.css +117 -0
  122. package/src/RedactoPrivacyCenter/styles/injectStyles.ts +1725 -0
  123. package/src/RedactoPrivacyCenter/styles/pcStyles.ts +813 -0
  124. package/src/RedactoPrivacyCenter/styles/responsive.ts +138 -0
  125. package/src/RedactoPrivacyCenter/styles/variables.css +133 -0
  126. package/src/RedactoPrivacyCenter/table/AdvancedTable.tsx +367 -0
  127. package/src/RedactoPrivacyCenter/table/AdvancedTablePagination.tsx +476 -0
  128. package/src/RedactoPrivacyCenter/table/index.ts +2 -0
  129. package/src/RedactoPrivacyCenter/types/images.d.ts +29 -0
  130. package/src/RedactoPrivacyCenter/ui/Footer.tsx +75 -0
  131. package/src/RedactoPrivacyCenter/ui/FormBlockWrapper.tsx +54 -0
  132. package/src/RedactoPrivacyCenter/ui/PCAccordion.tsx +93 -0
  133. package/src/RedactoPrivacyCenter/ui/PCActionIcon.tsx +47 -0
  134. package/src/RedactoPrivacyCenter/ui/PCAvatar.tsx +69 -0
  135. package/src/RedactoPrivacyCenter/ui/PCBadge.tsx +48 -0
  136. package/src/RedactoPrivacyCenter/ui/PCButton.tsx +77 -0
  137. package/src/RedactoPrivacyCenter/ui/PCCheckbox.tsx +55 -0
  138. package/src/RedactoPrivacyCenter/ui/PCCollapse.tsx +107 -0
  139. package/src/RedactoPrivacyCenter/ui/PCEmpty.tsx +35 -0
  140. package/src/RedactoPrivacyCenter/ui/PCInput.tsx +132 -0
  141. package/src/RedactoPrivacyCenter/ui/PCLoader.tsx +31 -0
  142. package/src/RedactoPrivacyCenter/ui/PCModal.tsx +106 -0
  143. package/src/RedactoPrivacyCenter/ui/PCPopover.tsx +173 -0
  144. package/src/RedactoPrivacyCenter/ui/PCSelect.tsx +387 -0
  145. package/src/RedactoPrivacyCenter/ui/PCTable.tsx +149 -0
  146. package/src/RedactoPrivacyCenter/ui/PCText.tsx +41 -0
  147. package/src/RedactoPrivacyCenter/ui/PCTextarea.tsx +43 -0
  148. package/src/RedactoPrivacyCenter/ui/PCTitle.tsx +37 -0
  149. package/src/RedactoPrivacyCenter/ui/PCTooltip.tsx +119 -0
  150. package/src/RedactoPrivacyCenter/ui/SimpleBar.tsx +25 -0
  151. package/src/RedactoPrivacyCenter/ui/StatusBadge.tsx +53 -0
  152. package/src/RedactoPrivacyCenter/ui/ThemeToggle.tsx +72 -0
  153. package/src/RedactoPrivacyCenter/ui/index.ts +18 -0
  154. package/src/RedactoPrivacyCenter/utils/cn.ts +28 -0
  155. package/src/RedactoPrivacyCenter/utils/date.ts +48 -0
  156. package/src/RedactoPrivacyCenter/utils/status.ts +111 -0
  157. package/src/RedactoPrivacyCenter/utils/toast.ts +130 -0
  158. package/src/privacy-center.ts +108 -0
  159. package/tsconfig.json +2 -0
  160. package/tsup.config.ts +16 -1
  161. package/.turbo/turbo-build.log +0 -21
@@ -0,0 +1,476 @@
1
+ import { useTranslation } from 'react-i18next';
2
+ import { type Table as ReactTableType } from '@tanstack/react-table';
3
+ import {
4
+ PiCaretDoubleLeftBold,
5
+ PiCaretDoubleRightBold,
6
+ PiCaretLeftBold,
7
+ PiCaretRightBold,
8
+ } from 'react-icons/pi';
9
+ import { PCActionIcon, PCSelect, PCText } from '../ui';
10
+ import { pcStyles } from '../styles/pcStyles';
11
+
12
+ const getVar = (varName: string): string => `var(${varName})`;
13
+
14
+ const pageSizeOptions = [
15
+ { value: 5, label: '5' },
16
+ { value: 10, label: '10' },
17
+ { value: 15, label: '15' },
18
+ { value: 20, label: '20' },
19
+ { value: 25, label: '25' },
20
+ ];
21
+
22
+ export type AdvancedTablePaginationProps<TData extends Record<string, any>> = {
23
+ table: ReactTableType<TData>;
24
+ showPageSize?: boolean;
25
+ showSelectedCount?: boolean;
26
+ className?: string;
27
+ };
28
+
29
+ export default function AdvancedTablePagination<
30
+ TData extends Record<string, any>,
31
+ >({
32
+ table,
33
+ showPageSize = true,
34
+ showSelectedCount = false,
35
+ className,
36
+ }: AdvancedTablePaginationProps<TData>) {
37
+ const { t } = useTranslation();
38
+ const currentPageSize = table.getState().pagination.pageSize;
39
+ const currentPageSizeOption = pageSizeOptions.find(opt => opt.value === currentPageSize) || pageSizeOptions[1];
40
+
41
+ const currentPage = table.getState().pagination.pageIndex + 1;
42
+ const totalPages = table.getPageCount();
43
+ const totalRows = table.getFilteredRowModel().rows.length;
44
+
45
+ // Preserve pagination visibility even when rows are temporarily empty during loading
46
+ const shouldShowPagination = totalPages > 0 || totalRows > 0;
47
+
48
+ // Don't render if there's truly no data and no pages
49
+ if (!shouldShowPagination && totalRows === 0 && totalPages === 0) {
50
+ return null;
51
+ }
52
+
53
+ return (
54
+ <div
55
+ className={className}
56
+ style={{
57
+ ...pcStyles.flex,
58
+ ...pcStyles.flexCol,
59
+ ...pcStyles.itemsCenter,
60
+ width: '100%',
61
+ paddingTop: getVar('--pc-spacing-sm'),
62
+ paddingBottom: getVar('--pc-spacing-sm'),
63
+ gap: getVar('--pc-spacing-sm'),
64
+ minHeight: '52px',
65
+ opacity: shouldShowPagination ? 1 : 0.5,
66
+ pointerEvents: shouldShowPagination ? 'auto' : 'none',
67
+ }}
68
+ >
69
+ {/* Mobile Layout: Stacked (screens < 640px) */}
70
+ <div style={{
71
+ ...pcStyles.flex,
72
+ ...pcStyles.flexCol,
73
+ ...pcStyles.itemsCenter,
74
+ ...pcStyles.gapSm,
75
+ width: '100%',
76
+ }} className="pc-block-xs pc-hidden-sm">
77
+ {showPageSize && (
78
+ <div style={{
79
+ ...pcStyles.flex,
80
+ ...pcStyles.itemsCenter,
81
+ ...pcStyles.gapSm,
82
+ width: '100%',
83
+ ...pcStyles.justifyCenter,
84
+ }}>
85
+ <PCText
86
+ size="sm"
87
+ color="secondary"
88
+ style={{
89
+ whiteSpace: 'nowrap',
90
+ flexShrink: 0,
91
+ }}
92
+ >
93
+ {t('rowsPerPage')}
94
+ </PCText>
95
+ <PCSelect
96
+ size="sm"
97
+ options={pageSizeOptions}
98
+ value={currentPageSizeOption}
99
+ onChange={(v) => {
100
+ if (v) {
101
+ table.setPageSize(Number(v.value));
102
+ }
103
+ }}
104
+ style={{
105
+ width: '56px',
106
+ minWidth: '56px',
107
+ flexShrink: 0,
108
+ }}
109
+ />
110
+ </div>
111
+ )}
112
+
113
+ <div style={{
114
+ ...pcStyles.flex,
115
+ ...pcStyles.itemsCenter,
116
+ ...pcStyles.gapSm,
117
+ flexWrap: 'wrap',
118
+ ...pcStyles.justifyCenter,
119
+ }}>
120
+ {totalPages > 0 && (
121
+ <div style={{
122
+ ...pcStyles.flex,
123
+ ...pcStyles.itemsCenter,
124
+ ...pcStyles.gapXs,
125
+ marginRight: getVar('--pc-spacing-xs'),
126
+ flexShrink: 0,
127
+ }}>
128
+ <PCText
129
+ size="sm"
130
+ color="secondary"
131
+ style={{ whiteSpace: 'nowrap' }}
132
+ >
133
+ {t('pageOf', { current: currentPage, total: totalPages })}
134
+ </PCText>
135
+ </div>
136
+ )}
137
+ <div style={{
138
+ display: 'grid',
139
+ gridTemplateColumns: 'repeat(4, 1fr)',
140
+ gap: '0.25rem',
141
+ flexShrink: 0,
142
+ }}>
143
+ <PCActionIcon
144
+ size="sm"
145
+ variant="outline"
146
+ aria-label={t('goToFirstPage')}
147
+ onClick={() => table.firstPage()}
148
+ disabled={!table.getCanPreviousPage()}
149
+ style={{
150
+ borderRadius: '0.5rem',
151
+ boxShadow: getVar('--pc-shadow-sm'),
152
+ borderColor: getVar('--pc-border-color'),
153
+ color: getVar('--pc-text-primary'),
154
+ backgroundColor: getVar('--pc-bg-primary'),
155
+ transition: 'all 0.2s ease',
156
+ }}
157
+ onMouseEnter={(e) => {
158
+ if (!table.getCanPreviousPage()) return;
159
+ e.currentTarget.style.backgroundColor = getVar('--pc-bg-hover');
160
+ e.currentTarget.style.borderColor = getVar('--pc-primary');
161
+ e.currentTarget.style.color = getVar('--pc-primary');
162
+ }}
163
+ onMouseLeave={(e) => {
164
+ e.currentTarget.style.backgroundColor = getVar('--pc-bg-primary');
165
+ e.currentTarget.style.borderColor = getVar('--pc-border-color');
166
+ e.currentTarget.style.color = getVar('--pc-text-primary');
167
+ }}
168
+ >
169
+ <PiCaretDoubleLeftBold size={14} />
170
+ </PCActionIcon>
171
+ <PCActionIcon
172
+ size="sm"
173
+ variant="outline"
174
+ aria-label={t('goToPreviousPage')}
175
+ onClick={() => table.previousPage()}
176
+ disabled={!table.getCanPreviousPage()}
177
+ style={{
178
+ borderRadius: '0.5rem',
179
+ boxShadow: getVar('--pc-shadow-sm'),
180
+ borderColor: getVar('--pc-border-color'),
181
+ color: getVar('--pc-text-primary'),
182
+ backgroundColor: getVar('--pc-bg-primary'),
183
+ transition: 'all 0.2s ease',
184
+ }}
185
+ onMouseEnter={(e) => {
186
+ if (!table.getCanPreviousPage()) return;
187
+ e.currentTarget.style.backgroundColor = getVar('--pc-bg-hover');
188
+ e.currentTarget.style.borderColor = getVar('--pc-primary');
189
+ e.currentTarget.style.color = getVar('--pc-primary');
190
+ }}
191
+ onMouseLeave={(e) => {
192
+ e.currentTarget.style.backgroundColor = getVar('--pc-bg-primary');
193
+ e.currentTarget.style.borderColor = getVar('--pc-border-color');
194
+ e.currentTarget.style.color = getVar('--pc-text-primary');
195
+ }}
196
+ >
197
+ <PiCaretLeftBold size={14} />
198
+ </PCActionIcon>
199
+ <PCActionIcon
200
+ size="sm"
201
+ variant="outline"
202
+ aria-label={t('goToNextPage')}
203
+ onClick={() => table.nextPage()}
204
+ disabled={!table.getCanNextPage()}
205
+ style={{
206
+ borderRadius: '0.5rem',
207
+ boxShadow: getVar('--pc-shadow-sm'),
208
+ borderColor: getVar('--pc-border-color'),
209
+ color: getVar('--pc-text-primary'),
210
+ backgroundColor: getVar('--pc-bg-primary'),
211
+ transition: 'all 0.2s ease',
212
+ }}
213
+ onMouseEnter={(e) => {
214
+ if (!table.getCanNextPage()) return;
215
+ e.currentTarget.style.backgroundColor = getVar('--pc-bg-hover');
216
+ e.currentTarget.style.borderColor = getVar('--pc-primary');
217
+ e.currentTarget.style.color = getVar('--pc-primary');
218
+ }}
219
+ onMouseLeave={(e) => {
220
+ e.currentTarget.style.backgroundColor = getVar('--pc-bg-primary');
221
+ e.currentTarget.style.borderColor = getVar('--pc-border-color');
222
+ e.currentTarget.style.color = getVar('--pc-text-primary');
223
+ }}
224
+ >
225
+ <PiCaretRightBold size={14} />
226
+ </PCActionIcon>
227
+ <PCActionIcon
228
+ size="sm"
229
+ variant="outline"
230
+ aria-label={t('goToLastPage')}
231
+ onClick={() => table.lastPage()}
232
+ disabled={!table.getCanNextPage()}
233
+ style={{
234
+ borderRadius: '0.5rem',
235
+ boxShadow: getVar('--pc-shadow-sm'),
236
+ borderColor: getVar('--pc-border-color'),
237
+ color: getVar('--pc-text-primary'),
238
+ backgroundColor: getVar('--pc-bg-primary'),
239
+ transition: 'all 0.2s ease',
240
+ }}
241
+ onMouseEnter={(e) => {
242
+ if (!table.getCanNextPage()) return;
243
+ e.currentTarget.style.backgroundColor = getVar('--pc-bg-hover');
244
+ e.currentTarget.style.borderColor = getVar('--pc-primary');
245
+ e.currentTarget.style.color = getVar('--pc-primary');
246
+ }}
247
+ onMouseLeave={(e) => {
248
+ e.currentTarget.style.backgroundColor = getVar('--pc-bg-primary');
249
+ e.currentTarget.style.borderColor = getVar('--pc-border-color');
250
+ e.currentTarget.style.color = getVar('--pc-text-primary');
251
+ }}
252
+ >
253
+ <PiCaretDoubleRightBold size={14} />
254
+ </PCActionIcon>
255
+ </div>
256
+ </div>
257
+ </div>
258
+
259
+ {/* Desktop/Tablet Layout: Horizontal (screens >= 640px) */}
260
+ <div style={{
261
+ ...pcStyles.flex,
262
+ ...pcStyles.itemsCenter,
263
+ ...pcStyles.justifyBetween,
264
+ width: '100%',
265
+ flexWrap: 'wrap',
266
+ gap: getVar('--pc-spacing-sm'),
267
+ }} className="pc-hidden-xs pc-flex-sm">
268
+ {/* Left Group: Rows per page */}
269
+ <div style={{
270
+ ...pcStyles.flex,
271
+ ...pcStyles.itemsCenter,
272
+ ...pcStyles.gapSm,
273
+ flexShrink: 0,
274
+ flexWrap: 'wrap',
275
+ }}>
276
+ {showPageSize && (
277
+ <div style={{
278
+ ...pcStyles.flex,
279
+ ...pcStyles.itemsCenter,
280
+ ...pcStyles.gapSm,
281
+ flexShrink: 0,
282
+ }}>
283
+ <PCText
284
+ size="sm"
285
+ color="secondary"
286
+ style={{
287
+ whiteSpace: 'nowrap',
288
+ flexShrink: 0,
289
+ }}
290
+ >
291
+ {t('rowsPerPage')}
292
+ </PCText>
293
+ <PCSelect
294
+ size="sm"
295
+ options={pageSizeOptions}
296
+ value={currentPageSizeOption}
297
+ onChange={(v) => {
298
+ if (v) {
299
+ table.setPageSize(Number(v.value));
300
+ }
301
+ }}
302
+ style={{
303
+ width: '56px',
304
+ minWidth: '56px',
305
+ flexShrink: 0,
306
+ }}
307
+ />
308
+ </div>
309
+ )}
310
+
311
+ {showSelectedCount && (
312
+ <PCText
313
+ size="sm"
314
+ color="secondary"
315
+ style={{
316
+ whiteSpace: 'nowrap',
317
+ flexShrink: 0,
318
+ }}
319
+ >
320
+ {t('rowsSelected', {
321
+ count: table.getFilteredSelectedRowModel().rows.length,
322
+ total: table.getFilteredRowModel().rows.length,
323
+ })}
324
+ </PCText>
325
+ )}
326
+ </div>
327
+
328
+ {/* Right Group: Page info + Navigation */}
329
+ <div style={{
330
+ ...pcStyles.flex,
331
+ ...pcStyles.itemsCenter,
332
+ ...pcStyles.gapSm,
333
+ flexShrink: 0,
334
+ flexWrap: 'wrap',
335
+ }}>
336
+ {totalPages > 0 && (
337
+ <div style={{
338
+ ...pcStyles.flex,
339
+ ...pcStyles.itemsCenter,
340
+ ...pcStyles.gapXs,
341
+ marginRight: getVar('--pc-spacing-xs'),
342
+ flexShrink: 0,
343
+ }}>
344
+ <PCText
345
+ size="sm"
346
+ color="secondary"
347
+ style={{ whiteSpace: 'nowrap' }}
348
+ >
349
+ {t('pageOf', { current: currentPage, total: totalPages })}
350
+ </PCText>
351
+ </div>
352
+ )}
353
+ <div style={{
354
+ display: 'grid',
355
+ gridTemplateColumns: 'repeat(4, 1fr)',
356
+ gap: '0.25rem',
357
+ flexShrink: 0,
358
+ }}>
359
+ <PCActionIcon
360
+ size="sm"
361
+ variant="outline"
362
+ aria-label={t('goToFirstPage')}
363
+ onClick={() => table.firstPage()}
364
+ disabled={!table.getCanPreviousPage()}
365
+ style={{
366
+ borderRadius: '0.5rem',
367
+ boxShadow: getVar('--pc-shadow-sm'),
368
+ borderColor: getVar('--pc-border-color'),
369
+ color: getVar('--pc-text-primary'),
370
+ backgroundColor: getVar('--pc-bg-primary'),
371
+ transition: 'all 0.2s ease',
372
+ }}
373
+ onMouseEnter={(e) => {
374
+ if (!table.getCanPreviousPage()) return;
375
+ e.currentTarget.style.backgroundColor = getVar('--pc-bg-hover');
376
+ e.currentTarget.style.borderColor = getVar('--pc-primary');
377
+ e.currentTarget.style.color = getVar('--pc-primary');
378
+ }}
379
+ onMouseLeave={(e) => {
380
+ e.currentTarget.style.backgroundColor = getVar('--pc-bg-primary');
381
+ e.currentTarget.style.borderColor = getVar('--pc-border-color');
382
+ e.currentTarget.style.color = getVar('--pc-text-primary');
383
+ }}
384
+ >
385
+ <PiCaretDoubleLeftBold size={14} />
386
+ </PCActionIcon>
387
+ <PCActionIcon
388
+ size="sm"
389
+ variant="outline"
390
+ aria-label={t('goToPreviousPage')}
391
+ onClick={() => table.previousPage()}
392
+ disabled={!table.getCanPreviousPage()}
393
+ style={{
394
+ borderRadius: '0.5rem',
395
+ boxShadow: getVar('--pc-shadow-sm'),
396
+ borderColor: getVar('--pc-border-color'),
397
+ color: getVar('--pc-text-primary'),
398
+ backgroundColor: getVar('--pc-bg-primary'),
399
+ transition: 'all 0.2s ease',
400
+ }}
401
+ onMouseEnter={(e) => {
402
+ if (!table.getCanPreviousPage()) return;
403
+ e.currentTarget.style.backgroundColor = getVar('--pc-bg-hover');
404
+ e.currentTarget.style.borderColor = getVar('--pc-primary');
405
+ e.currentTarget.style.color = getVar('--pc-primary');
406
+ }}
407
+ onMouseLeave={(e) => {
408
+ e.currentTarget.style.backgroundColor = getVar('--pc-bg-primary');
409
+ e.currentTarget.style.borderColor = getVar('--pc-border-color');
410
+ e.currentTarget.style.color = getVar('--pc-text-primary');
411
+ }}
412
+ >
413
+ <PiCaretLeftBold size={14} />
414
+ </PCActionIcon>
415
+ <PCActionIcon
416
+ size="sm"
417
+ variant="outline"
418
+ aria-label={t('goToNextPage')}
419
+ onClick={() => table.nextPage()}
420
+ disabled={!table.getCanNextPage()}
421
+ style={{
422
+ borderRadius: '0.5rem',
423
+ boxShadow: getVar('--pc-shadow-sm'),
424
+ borderColor: getVar('--pc-border-color'),
425
+ color: getVar('--pc-text-primary'),
426
+ backgroundColor: getVar('--pc-bg-primary'),
427
+ transition: 'all 0.2s ease',
428
+ }}
429
+ onMouseEnter={(e) => {
430
+ if (!table.getCanNextPage()) return;
431
+ e.currentTarget.style.backgroundColor = getVar('--pc-bg-hover');
432
+ e.currentTarget.style.borderColor = getVar('--pc-primary');
433
+ e.currentTarget.style.color = getVar('--pc-primary');
434
+ }}
435
+ onMouseLeave={(e) => {
436
+ e.currentTarget.style.backgroundColor = getVar('--pc-bg-primary');
437
+ e.currentTarget.style.borderColor = getVar('--pc-border-color');
438
+ e.currentTarget.style.color = getVar('--pc-text-primary');
439
+ }}
440
+ >
441
+ <PiCaretRightBold size={14} />
442
+ </PCActionIcon>
443
+ <PCActionIcon
444
+ size="sm"
445
+ variant="outline"
446
+ aria-label={t('goToLastPage')}
447
+ onClick={() => table.lastPage()}
448
+ disabled={!table.getCanNextPage()}
449
+ style={{
450
+ borderRadius: '0.5rem',
451
+ boxShadow: getVar('--pc-shadow-sm'),
452
+ borderColor: getVar('--pc-border-color'),
453
+ color: getVar('--pc-text-primary'),
454
+ backgroundColor: getVar('--pc-bg-primary'),
455
+ transition: 'all 0.2s ease',
456
+ }}
457
+ onMouseEnter={(e) => {
458
+ if (!table.getCanNextPage()) return;
459
+ e.currentTarget.style.backgroundColor = getVar('--pc-bg-hover');
460
+ e.currentTarget.style.borderColor = getVar('--pc-primary');
461
+ e.currentTarget.style.color = getVar('--pc-primary');
462
+ }}
463
+ onMouseLeave={(e) => {
464
+ e.currentTarget.style.backgroundColor = getVar('--pc-bg-primary');
465
+ e.currentTarget.style.borderColor = getVar('--pc-border-color');
466
+ e.currentTarget.style.color = getVar('--pc-text-primary');
467
+ }}
468
+ >
469
+ <PiCaretDoubleRightBold size={14} />
470
+ </PCActionIcon>
471
+ </div>
472
+ </div>
473
+ </div>
474
+ </div>
475
+ );
476
+ }
@@ -0,0 +1,2 @@
1
+ export { default as AdvancedTable } from './AdvancedTable';
2
+ export { default as AdvancedTablePagination } from './AdvancedTablePagination';
@@ -0,0 +1,29 @@
1
+ declare module "*.svg" {
2
+ const content: string;
3
+ export default content;
4
+ }
5
+
6
+ declare module "*.png" {
7
+ const content: string;
8
+ export default content;
9
+ }
10
+
11
+ declare module "*.jpg" {
12
+ const content: string;
13
+ export default content;
14
+ }
15
+
16
+ declare module "*.jpeg" {
17
+ const content: string;
18
+ export default content;
19
+ }
20
+
21
+ declare module "*.gif" {
22
+ const content: string;
23
+ export default content;
24
+ }
25
+
26
+ declare module "*.webp" {
27
+ const content: string;
28
+ export default content;
29
+ }
@@ -0,0 +1,75 @@
1
+ import { useTranslation } from 'react-i18next';
2
+ import { pcStyles } from '../styles/pcStyles';
3
+ import PoweredByRedacto from '../assets/poweredByRedacto.svg';
4
+ import { useTheme } from '../context/theme';
5
+
6
+ const getVar = (varName: string): string => `var(${varName})`;
7
+
8
+ export default function Footer() {
9
+ const { t } = useTranslation();
10
+ const { theme } = useTheme();
11
+
12
+ return (
13
+ <footer
14
+ style={{
15
+ ...pcStyles.flex,
16
+ ...pcStyles.justifyCenter,
17
+ width: '100%',
18
+ paddingTop: '0.25rem',
19
+ paddingBottom: '0.25rem',
20
+ }}
21
+ >
22
+ <div
23
+ style={{
24
+ ...pcStyles.flex,
25
+ ...pcStyles.flexCol,
26
+ ...pcStyles.itemsCenter,
27
+ ...pcStyles.justifyCenter,
28
+ ...pcStyles.gapSm,
29
+ ...pcStyles.textCenter,
30
+ minWidth: 'fit-content',
31
+ }}
32
+ >
33
+ <span
34
+ style={{
35
+ ...pcStyles.fontWeightBold,
36
+ color: getVar('--pc-text-secondary'),
37
+ fontSize: 'clamp(0.75rem, 1.5vw, 1rem)',
38
+ lineHeight: 1.2,
39
+ }}
40
+ >
41
+ {t('poweredBy')}
42
+ </span>
43
+ <div
44
+ style={{
45
+ display: 'inline-flex',
46
+ alignItems: 'center',
47
+ justifyContent: 'center',
48
+ minHeight: '1.75rem',
49
+ padding:
50
+ theme === 'dark' ? '0.25rem 0.5rem' : 0,
51
+ backgroundColor:
52
+ theme === 'dark' ? 'rgba(255, 255, 255, 0.92)' : 'transparent',
53
+ borderRadius: '9999px',
54
+ boxShadow:
55
+ theme === 'dark'
56
+ ? '0 8px 18px rgba(2, 6, 23, 0.28)'
57
+ : 'none',
58
+ }}
59
+ >
60
+ <img
61
+ src={PoweredByRedacto}
62
+ alt={t('redactoLogoAlt')}
63
+ style={{
64
+ height: 'clamp(1.125rem, 2.5vw, 1.75rem)',
65
+ width: 'auto',
66
+ objectFit: 'contain',
67
+ display: 'block',
68
+ filter: 'drop-shadow(0 1px 1px rgba(15, 23, 42, 0.06))',
69
+ }}
70
+ />
71
+ </div>
72
+ </div>
73
+ </footer>
74
+ );
75
+ }
@@ -0,0 +1,54 @@
1
+ import { PCTitle, PCText } from './index';
2
+ import { pcStyles } from '../styles/pcStyles';
3
+
4
+ const getVar = (varName: string): string => `var(${varName})`;
5
+
6
+ // form block wrapper
7
+ export function FormBlockWrapper({
8
+ title,
9
+ description,
10
+ children,
11
+ className,
12
+ inputClassName,
13
+ }: React.PropsWithChildren<{
14
+ title?: string;
15
+ description?: string;
16
+ className?: string;
17
+ inputClassName?: string;
18
+ }>) {
19
+ return (
20
+ <section
21
+ className={className}
22
+ style={{
23
+ display: 'flex',
24
+ flexDirection: 'column',
25
+ width: '100%',
26
+ gap: pcStyles.gapMd.gap,
27
+ }}
28
+ >
29
+ {title && (
30
+ <header style={{ marginBottom: pcStyles.mbSm.marginBottom }}>
31
+ <PCTitle as="h5" style={{ ...pcStyles.fontWeightSemibold, color: getVar('--pc-text-primary') }}>
32
+ {title}
33
+ </PCTitle>
34
+ {description && (
35
+ <PCText size="sm" color="secondary" style={{ marginTop: pcStyles.mtXs.marginTop }}>
36
+ {description}
37
+ </PCText>
38
+ )}
39
+ </header>
40
+ )}
41
+ <div
42
+ className={inputClassName}
43
+ style={{
44
+ width: '100%',
45
+ display: 'flex',
46
+ flexDirection: 'column',
47
+ gap: pcStyles.gapMd.gap,
48
+ }}
49
+ >
50
+ {children}
51
+ </div>
52
+ </section>
53
+ );
54
+ }