@squaredr/fieldcraft-pro 1.1.1 → 1.3.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.
@@ -1,7 +1,7 @@
1
1
  import { cn } from './chunk-QQ4JZGTD.mjs';
2
2
  import { requireLicense } from './chunk-VECQKSWS.mjs';
3
- import { useState } from 'react';
4
- import { Button, Separator } from '@squaredr/fieldcraft-react';
3
+ import { useState, useEffect } from 'react';
4
+ import { Button, Separator, Input, Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '@squaredr/fieldcraft-react';
5
5
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
6
 
7
7
  // src/response-viewer/clinical-display-data.ts
@@ -732,16 +732,24 @@ function formatFallbackValue(value) {
732
732
  }
733
733
 
734
734
  // src/response-viewer/export-utils.ts
735
- function exportToCsv(schema, responses, filename = "responses.csv") {
735
+ function buildCsvContent(schema, responses, options = {}) {
736
+ const { dateFormat = "locale", columnLabels } = options;
736
737
  const questions = getExportableQuestions(schema);
737
- const headers = ["Submitted", ...questions.map((q) => q.label), "Score"];
738
+ const headers = [
739
+ "Submitted",
740
+ ...questions.map((q) => columnLabels?.[q.id] ?? q.label),
741
+ "Score"
742
+ ];
738
743
  const rows = responses.map((r) => {
739
- const submitted = new Date(r.submittedAt).toLocaleString();
744
+ const submitted = dateFormat === "iso" ? new Date(r.submittedAt).toISOString() : new Date(r.submittedAt).toLocaleString();
740
745
  const values = questions.map((q) => formatExportValue(r.values[q.id], q.type));
741
746
  const score = r.totalScore != null ? String(r.totalScore) : "";
742
747
  return [submitted, ...values, score];
743
748
  });
744
- const csvContent = [headers, ...rows].map((row) => row.map(escapeCsvField).join(",")).join("\n");
749
+ return [headers, ...rows].map((row) => row.map(escapeCsvField).join(",")).join("\n");
750
+ }
751
+ function exportToCsv(schema, responses, filename = "responses.csv", options = {}) {
752
+ const csvContent = buildCsvContent(schema, responses, options);
745
753
  downloadBlob(csvContent, filename, "text/csv;charset=utf-8;");
746
754
  }
747
755
  function exportToJson(responses, filename = "responses.json") {
@@ -836,15 +844,145 @@ function downloadBlob(content, filename, mimeType) {
836
844
  document.body.removeChild(link);
837
845
  URL.revokeObjectURL(url);
838
846
  }
847
+
848
+ // src/response-viewer/pagination-utils.ts
849
+ function paginate(items, currentPage, pageSize) {
850
+ const totalItems = items.length;
851
+ const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
852
+ const page = Math.max(1, Math.min(currentPage, totalPages));
853
+ const startIndex = (page - 1) * pageSize;
854
+ const endIndex = Math.min(startIndex + pageSize, totalItems);
855
+ const pageItems = items.slice(startIndex, endIndex);
856
+ return {
857
+ pageItems,
858
+ currentPage: page,
859
+ totalPages,
860
+ startItem: totalItems === 0 ? 0 : startIndex + 1,
861
+ endItem: endIndex,
862
+ totalItems,
863
+ showPagination: totalItems > pageSize
864
+ };
865
+ }
866
+
867
+ // src/response-viewer/filter-utils.ts
868
+ function createEmptyFilterState() {
869
+ return { filters: [], dateRange: {} };
870
+ }
871
+ function hasActiveFilters(state) {
872
+ return state.filters.length > 0 || !!state.dateRange.from || !!state.dateRange.to;
873
+ }
874
+ function applyFilters(responses, state) {
875
+ if (!hasActiveFilters(state)) return responses;
876
+ return responses.filter((r) => {
877
+ if (!matchesDateRange(r.submittedAt, state.dateRange)) return false;
878
+ for (const filter of state.filters) {
879
+ if (!matchesFieldFilter(r.values[filter.fieldId], filter)) return false;
880
+ }
881
+ return true;
882
+ });
883
+ }
884
+ function matchesDateRange(submittedAt, range) {
885
+ if (!range.from && !range.to) return true;
886
+ const submitted = new Date(submittedAt);
887
+ if (range.from) {
888
+ const from = new Date(range.from);
889
+ from.setHours(0, 0, 0, 0);
890
+ if (submitted < from) return false;
891
+ }
892
+ if (range.to) {
893
+ const to = new Date(range.to);
894
+ to.setHours(23, 59, 59, 999);
895
+ if (submitted > to) return false;
896
+ }
897
+ return true;
898
+ }
899
+ function matchesFieldFilter(value, filter) {
900
+ switch (filter.operator) {
901
+ case "equals":
902
+ if (value == null) return false;
903
+ return String(value).toLowerCase() === String(filter.value).toLowerCase();
904
+ case "contains":
905
+ if (value == null) return false;
906
+ return String(value).toLowerCase().includes(String(filter.value).toLowerCase());
907
+ case "gt":
908
+ if (typeof value !== "number") return false;
909
+ return value > Number(filter.value);
910
+ case "lt":
911
+ if (typeof value !== "number") return false;
912
+ return value < Number(filter.value);
913
+ case "is_true":
914
+ return value === true || value === "true" || value === "agreed";
915
+ case "is_false":
916
+ return value === false || value === "false" || value == null;
917
+ default:
918
+ return true;
919
+ }
920
+ }
921
+ var PAGE_SIZE_OPTIONS = [10, 25, 50, 100];
922
+ var FIELD_FILTER_OPERATORS = {
923
+ text: [
924
+ { label: "equals", value: "equals" },
925
+ { label: "contains", value: "contains" }
926
+ ],
927
+ number: [
928
+ { label: "equals", value: "equals" },
929
+ { label: "greater than", value: "gt" },
930
+ { label: "less than", value: "lt" }
931
+ ],
932
+ boolean: [
933
+ { label: "is true", value: "is_true" },
934
+ { label: "is false", value: "is_false" }
935
+ ],
936
+ select: [
937
+ { label: "equals", value: "equals" }
938
+ ]
939
+ };
940
+ function getOperatorsForType(type) {
941
+ if (type === "number" || type === "slider" || type === "rating" || type === "nps" || type === "opinion_scale" || type === "pain_scale") {
942
+ return FIELD_FILTER_OPERATORS.number;
943
+ }
944
+ if (type === "boolean" || type === "consent") {
945
+ return FIELD_FILTER_OPERATORS.boolean;
946
+ }
947
+ if (type === "single_select" || type === "dropdown" || type === "country_select") {
948
+ return FIELD_FILTER_OPERATORS.select;
949
+ }
950
+ return FIELD_FILTER_OPERATORS.text;
951
+ }
952
+ function operatorNeedsValue(operator) {
953
+ return operator !== "is_true" && operator !== "is_false";
954
+ }
839
955
  function ResponseViewerInner({
840
956
  schema,
841
957
  responses,
842
958
  onResponseSelect,
843
959
  height = "500px",
844
- width = "100%"
960
+ width = "100%",
961
+ filename,
962
+ dateFormat,
963
+ columnLabels,
964
+ onExport,
965
+ pageSize = 25
845
966
  }) {
846
967
  const [viewMode, setViewMode] = useState("table");
847
968
  const [selectedResponse, setSelectedResponse] = useState(null);
969
+ const [currentPage, setCurrentPage] = useState(1);
970
+ const [effectivePageSize, setEffectivePageSize] = useState(pageSize);
971
+ const [filterState, setFilterState] = useState(createEmptyFilterState);
972
+ const [showFilterPanel, setShowFilterPanel] = useState(false);
973
+ const [draftFieldId, setDraftFieldId] = useState("");
974
+ const [draftOperator, setDraftOperator] = useState("contains");
975
+ const [draftValue, setDraftValue] = useState("");
976
+ useEffect(() => {
977
+ setCurrentPage(1);
978
+ }, [responses]);
979
+ useEffect(() => {
980
+ setEffectivePageSize(pageSize);
981
+ setCurrentPage(1);
982
+ }, [pageSize]);
983
+ const isFiltered = hasActiveFilters(filterState);
984
+ const filteredResponses = applyFilters(responses, filterState);
985
+ const pag = paginate(filteredResponses, currentPage, effectivePageSize);
848
986
  function handleSelect(response) {
849
987
  setSelectedResponse(response);
850
988
  onResponseSelect?.(response);
@@ -852,6 +990,45 @@ function ResponseViewerInner({
852
990
  function handleBack() {
853
991
  setSelectedResponse(null);
854
992
  }
993
+ function handlePageSizeChange(newSize) {
994
+ setEffectivePageSize(Number(newSize));
995
+ setCurrentPage(1);
996
+ }
997
+ function handleAddFilter() {
998
+ if (!draftFieldId) return;
999
+ if (operatorNeedsValue(draftOperator) && !draftValue) return;
1000
+ const newFilter = {
1001
+ fieldId: draftFieldId,
1002
+ operator: draftOperator,
1003
+ value: draftOperator === "gt" || draftOperator === "lt" ? Number(draftValue) : draftValue
1004
+ };
1005
+ setFilterState((prev) => ({
1006
+ ...prev,
1007
+ filters: [...prev.filters, newFilter]
1008
+ }));
1009
+ setDraftFieldId("");
1010
+ setDraftOperator("contains");
1011
+ setDraftValue("");
1012
+ setCurrentPage(1);
1013
+ }
1014
+ function handleRemoveFilter(index) {
1015
+ setFilterState((prev) => ({
1016
+ ...prev,
1017
+ filters: prev.filters.filter((_, i) => i !== index)
1018
+ }));
1019
+ setCurrentPage(1);
1020
+ }
1021
+ function handleDateRangeChange(field, value) {
1022
+ setFilterState((prev) => ({
1023
+ ...prev,
1024
+ dateRange: { ...prev.dateRange, [field]: value || void 0 }
1025
+ }));
1026
+ setCurrentPage(1);
1027
+ }
1028
+ function handleClearAllFilters() {
1029
+ setFilterState(createEmptyFilterState());
1030
+ setCurrentPage(1);
1031
+ }
855
1032
  const questions = getAllQuestions2(schema);
856
1033
  function getFields(response) {
857
1034
  return questions.map((q) => ({
@@ -869,12 +1046,8 @@ function ResponseViewerInner({
869
1046
  className: "flex flex-col border border-border rounded-lg overflow-hidden bg-background text-foreground",
870
1047
  style: { height: heightValue, width: widthValue },
871
1048
  children: [
872
- !selectedResponse && /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-center px-3 py-2 border-b border-border", children: [
873
- /* @__PURE__ */ jsxs("div", { className: "text-xs text-muted-foreground", children: [
874
- responses.length,
875
- " response",
876
- responses.length !== 1 ? "s" : ""
877
- ] }),
1049
+ !selectedResponse && /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-x-2 gap-y-1 px-3 py-2 border-b border-border", children: [
1050
+ /* @__PURE__ */ jsx("div", { className: "text-xs text-muted-foreground mr-auto", children: isFiltered ? `Showing ${filteredResponses.length} of ${responses.length} responses (filtered)` : `${responses.length} response${responses.length !== 1 ? "s" : ""}` }),
878
1051
  /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
879
1052
  /* @__PURE__ */ jsx(
880
1053
  Button,
@@ -901,15 +1074,50 @@ function ResponseViewerInner({
901
1074
  onClick: () => setViewMode("card"),
902
1075
  children: "Cards"
903
1076
  }
1077
+ )
1078
+ ] }),
1079
+ /* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "h-5 hidden sm:block" }),
1080
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
1081
+ /* @__PURE__ */ jsxs(
1082
+ Button,
1083
+ {
1084
+ variant: showFilterPanel ? "secondary" : "outline",
1085
+ size: "sm",
1086
+ className: cn(
1087
+ "fc-rv-filter__button h-7 text-xs",
1088
+ showFilterPanel && "font-semibold border border-ring"
1089
+ ),
1090
+ onClick: () => setShowFilterPanel((v) => !v),
1091
+ children: [
1092
+ "Filter",
1093
+ isFiltered ? ` (${filterState.filters.length + (filterState.dateRange.from || filterState.dateRange.to ? 1 : 0)})` : ""
1094
+ ]
1095
+ }
904
1096
  ),
905
- /* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "h-5 mx-1" }),
1097
+ isFiltered && /* @__PURE__ */ jsx(
1098
+ Button,
1099
+ {
1100
+ variant: "ghost",
1101
+ size: "sm",
1102
+ className: "h-7 text-xs text-destructive",
1103
+ onClick: handleClearAllFilters,
1104
+ children: "Clear all"
1105
+ }
1106
+ )
1107
+ ] }),
1108
+ /* @__PURE__ */ jsx(Separator, { orientation: "vertical", className: "h-5 hidden sm:block" }),
1109
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
906
1110
  /* @__PURE__ */ jsx(
907
1111
  Button,
908
1112
  {
909
1113
  variant: "outline",
910
1114
  size: "sm",
911
1115
  className: "h-7 text-xs",
912
- onClick: () => exportToCsv(schema, responses),
1116
+ onClick: () => {
1117
+ const csvFilename = filename ? filename.replace(/\.\w+$/, ".csv") : "responses.csv";
1118
+ exportToCsv(schema, responses, csvFilename, { dateFormat, columnLabels });
1119
+ onExport?.("csv", responses.length);
1120
+ },
913
1121
  disabled: responses.length === 0,
914
1122
  children: "Export CSV"
915
1123
  }
@@ -920,14 +1128,146 @@ function ResponseViewerInner({
920
1128
  variant: "outline",
921
1129
  size: "sm",
922
1130
  className: "h-7 text-xs",
923
- onClick: () => exportToJson(responses),
1131
+ onClick: () => {
1132
+ const jsonFilename = filename ? filename.replace(/\.\w+$/, ".json") : "responses.json";
1133
+ exportToJson(responses, jsonFilename);
1134
+ onExport?.("json", responses.length);
1135
+ },
924
1136
  disabled: responses.length === 0,
925
1137
  children: "Export JSON"
926
1138
  }
927
1139
  )
928
1140
  ] })
929
1141
  ] }),
930
- /* @__PURE__ */ jsx("div", { className: cn("flex-1 overflow-auto", selectedResponse && "p-4"), children: selectedResponse ? /* @__PURE__ */ jsx(
1142
+ !selectedResponse && showFilterPanel && /* @__PURE__ */ jsxs("div", { className: "fc-rv-filter__panel px-3 py-2 border-b border-border bg-muted/50", children: [
1143
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2 mb-2", children: [
1144
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground w-16 shrink-0", children: "Date:" }),
1145
+ /* @__PURE__ */ jsx(
1146
+ Input,
1147
+ {
1148
+ type: "date",
1149
+ className: "h-7 text-xs w-36",
1150
+ value: filterState.dateRange.from ?? "",
1151
+ onChange: (e) => handleDateRangeChange("from", e.target.value)
1152
+ }
1153
+ ),
1154
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "to" }),
1155
+ /* @__PURE__ */ jsx(
1156
+ Input,
1157
+ {
1158
+ type: "date",
1159
+ className: "h-7 text-xs w-36",
1160
+ value: filterState.dateRange.to ?? "",
1161
+ onChange: (e) => handleDateRangeChange("to", e.target.value)
1162
+ }
1163
+ )
1164
+ ] }),
1165
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
1166
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground w-16 shrink-0", children: "Field:" }),
1167
+ /* @__PURE__ */ jsxs(
1168
+ Select,
1169
+ {
1170
+ value: draftFieldId || void 0,
1171
+ onValueChange: (val) => {
1172
+ setDraftFieldId(val);
1173
+ const q = questions.find((q2) => q2.id === val);
1174
+ if (q) {
1175
+ const ops = getOperatorsForType(q.type);
1176
+ setDraftOperator(ops[0].value);
1177
+ }
1178
+ setDraftValue("");
1179
+ },
1180
+ children: [
1181
+ /* @__PURE__ */ jsx(SelectTrigger, { size: "sm", className: "h-7 text-xs w-40", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Select field" }) }),
1182
+ /* @__PURE__ */ jsx(SelectContent, { children: questions.map((q) => /* @__PURE__ */ jsx(SelectItem, { value: q.id, children: q.label }, q.id)) })
1183
+ ]
1184
+ }
1185
+ ),
1186
+ draftFieldId && /* @__PURE__ */ jsxs(Fragment, { children: [
1187
+ /* @__PURE__ */ jsxs(
1188
+ Select,
1189
+ {
1190
+ value: draftOperator,
1191
+ onValueChange: (val) => setDraftOperator(val),
1192
+ children: [
1193
+ /* @__PURE__ */ jsx(SelectTrigger, { size: "sm", className: "h-7 text-xs w-32", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
1194
+ /* @__PURE__ */ jsx(SelectContent, { children: getOperatorsForType(
1195
+ questions.find((q) => q.id === draftFieldId)?.type ?? "short_text"
1196
+ ).map((op) => /* @__PURE__ */ jsx(SelectItem, { value: op.value, children: op.label }, op.value)) })
1197
+ ]
1198
+ }
1199
+ ),
1200
+ operatorNeedsValue(draftOperator) && /* @__PURE__ */ jsx(
1201
+ Input,
1202
+ {
1203
+ className: "h-7 text-xs w-32",
1204
+ placeholder: "Value",
1205
+ value: draftValue,
1206
+ onChange: (e) => setDraftValue(e.target.value),
1207
+ onKeyDown: (e) => e.key === "Enter" && handleAddFilter()
1208
+ }
1209
+ ),
1210
+ /* @__PURE__ */ jsx(
1211
+ Button,
1212
+ {
1213
+ variant: "outline",
1214
+ size: "sm",
1215
+ className: "h-7 text-xs",
1216
+ onClick: handleAddFilter,
1217
+ children: "Add"
1218
+ }
1219
+ )
1220
+ ] })
1221
+ ] })
1222
+ ] }),
1223
+ !selectedResponse && isFiltered && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 px-3 py-1.5 border-b border-border flex-wrap", children: [
1224
+ filterState.dateRange.from && /* @__PURE__ */ jsxs(
1225
+ "span",
1226
+ {
1227
+ className: "fc-rv-filter__chip inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-accent text-xs text-foreground cursor-pointer hover:bg-destructive/20",
1228
+ onClick: () => handleDateRangeChange("from", ""),
1229
+ children: [
1230
+ "From: ",
1231
+ filterState.dateRange.from,
1232
+ " \xD7"
1233
+ ]
1234
+ }
1235
+ ),
1236
+ filterState.dateRange.to && /* @__PURE__ */ jsxs(
1237
+ "span",
1238
+ {
1239
+ className: "fc-rv-filter__chip inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-accent text-xs text-foreground cursor-pointer hover:bg-destructive/20",
1240
+ onClick: () => handleDateRangeChange("to", ""),
1241
+ children: [
1242
+ "To: ",
1243
+ filterState.dateRange.to,
1244
+ " \xD7"
1245
+ ]
1246
+ }
1247
+ ),
1248
+ filterState.filters.map((f, i) => {
1249
+ const q = questions.find((q2) => q2.id === f.fieldId);
1250
+ const label = q?.label ?? f.fieldId;
1251
+ const opLabel = f.operator.replace("_", " ");
1252
+ const valueStr = operatorNeedsValue(f.operator) ? ` "${f.value}"` : "";
1253
+ return /* @__PURE__ */ jsxs(
1254
+ "span",
1255
+ {
1256
+ className: "fc-rv-filter__chip inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-accent text-xs text-foreground cursor-pointer hover:bg-destructive/20",
1257
+ onClick: () => handleRemoveFilter(i),
1258
+ children: [
1259
+ label,
1260
+ " ",
1261
+ opLabel,
1262
+ valueStr,
1263
+ " \xD7"
1264
+ ]
1265
+ },
1266
+ i
1267
+ );
1268
+ })
1269
+ ] }),
1270
+ /* @__PURE__ */ jsx("div", { className: cn("flex-1 min-w-0 overflow-auto", selectedResponse && "p-4"), children: selectedResponse ? /* @__PURE__ */ jsx(
931
1271
  ResponseDetail,
932
1272
  {
933
1273
  response: selectedResponse,
@@ -938,11 +1278,11 @@ function ResponseViewerInner({
938
1278
  ResponseTable,
939
1279
  {
940
1280
  schema,
941
- responses,
1281
+ responses: pag.pageItems,
942
1282
  onRowClick: handleSelect
943
1283
  }
944
1284
  ) : /* @__PURE__ */ jsxs("div", { className: "grid gap-3 p-3 grid-cols-[repeat(auto-fill,minmax(280px,1fr))]", children: [
945
- responses.map((response, idx) => /* @__PURE__ */ jsx(
1285
+ pag.pageItems.map((response, idx) => /* @__PURE__ */ jsx(
946
1286
  ResponseCard,
947
1287
  {
948
1288
  response,
@@ -951,8 +1291,63 @@ function ResponseViewerInner({
951
1291
  },
952
1292
  response.sessionToken || idx
953
1293
  )),
954
- responses.length === 0 && /* @__PURE__ */ jsx("div", { className: "p-8 text-center text-muted-foreground", children: "No responses yet" })
955
- ] }) })
1294
+ filteredResponses.length === 0 && /* @__PURE__ */ jsx("div", { className: "p-8 text-center text-muted-foreground", children: isFiltered ? "No matching responses" : "No responses yet" })
1295
+ ] }) }),
1296
+ !selectedResponse && pag.showPagination && /* @__PURE__ */ jsxs("div", { className: "fc-rv-pagination flex flex-wrap items-center gap-x-2 gap-y-1 px-3 py-2 border-t border-border", children: [
1297
+ /* @__PURE__ */ jsxs("div", { className: "fc-rv-pagination__info text-xs text-muted-foreground mr-auto", children: [
1298
+ "Showing ",
1299
+ pag.startItem,
1300
+ "\u2013",
1301
+ pag.endItem,
1302
+ " of ",
1303
+ pag.totalItems,
1304
+ " responses"
1305
+ ] }),
1306
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
1307
+ /* @__PURE__ */ jsxs("div", { className: "fc-rv-pagination__size-select flex items-center gap-1", children: [
1308
+ /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: "Per page:" }),
1309
+ /* @__PURE__ */ jsxs(
1310
+ Select,
1311
+ {
1312
+ value: String(effectivePageSize),
1313
+ onValueChange: handlePageSizeChange,
1314
+ children: [
1315
+ /* @__PURE__ */ jsx(SelectTrigger, { size: "sm", className: "h-7 w-16 text-xs", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
1316
+ /* @__PURE__ */ jsx(SelectContent, { children: PAGE_SIZE_OPTIONS.map((size) => /* @__PURE__ */ jsx(SelectItem, { value: String(size), children: size }, size)) })
1317
+ ]
1318
+ }
1319
+ )
1320
+ ] }),
1321
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-muted-foreground", children: [
1322
+ "Page ",
1323
+ pag.currentPage,
1324
+ " of ",
1325
+ pag.totalPages
1326
+ ] }),
1327
+ /* @__PURE__ */ jsx(
1328
+ Button,
1329
+ {
1330
+ variant: "outline",
1331
+ size: "sm",
1332
+ className: "fc-rv-pagination__button h-7 text-xs",
1333
+ onClick: () => setCurrentPage((p) => p - 1),
1334
+ disabled: pag.currentPage <= 1,
1335
+ children: "Previous"
1336
+ }
1337
+ ),
1338
+ /* @__PURE__ */ jsx(
1339
+ Button,
1340
+ {
1341
+ variant: "outline",
1342
+ size: "sm",
1343
+ className: "fc-rv-pagination__button h-7 text-xs",
1344
+ onClick: () => setCurrentPage((p) => p + 1),
1345
+ disabled: pag.currentPage >= pag.totalPages,
1346
+ children: "Next"
1347
+ }
1348
+ )
1349
+ ] })
1350
+ ] })
956
1351
  ]
957
1352
  }
958
1353
  );