Skip to content

Commit 0c20399

Browse files
committed
feat: Add support for product export in UI
1 parent df734a3 commit 0c20399

File tree

16 files changed

+559
-334
lines changed

16 files changed

+559
-334
lines changed

packages/admin-next/dashboard/src/components/table/data-table/data-table-filter/data-table-filter.tsx

+12-3
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,15 @@ export type Filter = {
4141

4242
type DataTableFilterProps = {
4343
filters: Filter[]
44+
readonly?: boolean
4445
prefix?: string
4546
}
4647

47-
export const DataTableFilter = ({ filters, prefix }: DataTableFilterProps) => {
48+
export const DataTableFilter = ({
49+
filters,
50+
readonly,
51+
prefix,
52+
}: DataTableFilterProps) => {
4853
const { t } = useTranslation()
4954
const [searchParams] = useSearchParams()
5055
const [open, setOpen] = useState(false)
@@ -127,6 +132,7 @@ export const DataTableFilter = ({ filters, prefix }: DataTableFilterProps) => {
127132
key={filter.key}
128133
filter={filter}
129134
prefix={prefix}
135+
readonly={readonly}
130136
options={filter.options}
131137
multiple={filter.multiple}
132138
searchable={filter.searchable}
@@ -139,6 +145,7 @@ export const DataTableFilter = ({ filters, prefix }: DataTableFilterProps) => {
139145
key={filter.key}
140146
filter={filter}
141147
prefix={prefix}
148+
readonly={readonly}
142149
openOnMount={filter.openOnMount}
143150
/>
144151
)
@@ -148,6 +155,7 @@ export const DataTableFilter = ({ filters, prefix }: DataTableFilterProps) => {
148155
key={filter.key}
149156
filter={filter}
150157
prefix={prefix}
158+
readonly={readonly}
151159
openOnMount={filter.openOnMount}
152160
/>
153161
)
@@ -157,14 +165,15 @@ export const DataTableFilter = ({ filters, prefix }: DataTableFilterProps) => {
157165
key={filter.key}
158166
filter={filter}
159167
prefix={prefix}
168+
readonly={readonly}
160169
openOnMount={filter.openOnMount}
161170
/>
162171
)
163172
default:
164173
break
165174
}
166175
})}
167-
{availableFilters.length > 0 && (
176+
{!readonly && availableFilters.length > 0 && (
168177
<Popover.Root modal open={open} onOpenChange={setOpen}>
169178
<Popover.Trigger asChild id="filters_menu_trigger">
170179
<Button size="small" variant="secondary">
@@ -208,7 +217,7 @@ export const DataTableFilter = ({ filters, prefix }: DataTableFilterProps) => {
208217
</Popover.Portal>
209218
</Popover.Root>
210219
)}
211-
{activeFilters.length > 0 && (
220+
{!readonly && activeFilters.length > 0 && (
212221
<ClearAllFilters filters={filters} prefix={prefix} />
213222
)}
214223
</div>

packages/admin-next/dashboard/src/components/table/data-table/data-table-filter/date-filter.tsx

+120-104
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ type DateComparisonOperator = {
3535
export const DateFilter = ({
3636
filter,
3737
prefix,
38+
readonly,
3839
openOnMount,
3940
}: DateFilterProps) => {
4041
const [open, setOpen] = useState(openOnMount)
@@ -118,123 +119,136 @@ export const DateFilter = ({
118119

119120
return (
120121
<Popover.Root modal open={open} onOpenChange={handleOpenChange}>
121-
<DateDisplay label={label} value={displayValue} onRemove={handleRemove} />
122-
<Popover.Portal>
123-
<Popover.Content
124-
data-name="date_filter_content"
125-
align="start"
126-
sideOffset={8}
127-
collisionPadding={24}
128-
className={clx(
129-
"bg-ui-bg-base text-ui-fg-base shadow-elevation-flyout h-full max-h-[var(--radix-popper-available-height)] w-[300px] overflow-auto rounded-lg"
130-
)}
131-
onInteractOutside={(e) => {
132-
if (e.target instanceof HTMLElement) {
133-
if (
134-
e.target.attributes.getNamedItem("data-name")?.value ===
135-
"filters_menu_content"
136-
) {
137-
e.preventDefault()
122+
<DateDisplay
123+
label={label}
124+
value={displayValue}
125+
onRemove={handleRemove}
126+
readonly={readonly}
127+
/>
128+
{!readonly && (
129+
<Popover.Portal>
130+
<Popover.Content
131+
data-name="date_filter_content"
132+
align="start"
133+
sideOffset={8}
134+
collisionPadding={24}
135+
className={clx(
136+
"bg-ui-bg-base text-ui-fg-base shadow-elevation-flyout h-full max-h-[var(--radix-popper-available-height)] w-[300px] overflow-auto rounded-lg"
137+
)}
138+
onInteractOutside={(e) => {
139+
if (e.target instanceof HTMLElement) {
140+
if (
141+
e.target.attributes.getNamedItem("data-name")?.value ===
142+
"filters_menu_content"
143+
) {
144+
e.preventDefault()
145+
}
138146
}
139-
}
140-
}}
141-
>
142-
<ul className="w-full p-1">
143-
{presets.map((preset) => {
144-
const isSelected = selectedParams
145-
.get()
146-
.includes(JSON.stringify(preset.value))
147-
return (
148-
<li key={preset.label}>
149-
<button
150-
className="bg-ui-bg-base hover:bg-ui-bg-base-hover focus-visible:bg-ui-bg-base-pressed text-ui-fg-base data-[disabled]:text-ui-fg-disabled txt-compact-small relative flex w-full cursor-pointer select-none items-center rounded-md px-2 py-1.5 outline-none transition-colors data-[disabled]:pointer-events-none"
151-
type="button"
152-
onClick={() => {
153-
handleSelectPreset(preset.value)
154-
}}
155-
>
156-
<div
157-
className={clx(
158-
"transition-fg flex h-5 w-5 items-center justify-center",
159-
{
160-
"[&_svg]:invisible": !isSelected,
161-
}
162-
)}
147+
}}
148+
>
149+
<ul className="w-full p-1">
150+
{presets.map((preset) => {
151+
const isSelected = selectedParams
152+
.get()
153+
.includes(JSON.stringify(preset.value))
154+
return (
155+
<li key={preset.label}>
156+
<button
157+
className="bg-ui-bg-base hover:bg-ui-bg-base-hover focus-visible:bg-ui-bg-base-pressed text-ui-fg-base data-[disabled]:text-ui-fg-disabled txt-compact-small relative flex w-full cursor-pointer select-none items-center rounded-md px-2 py-1.5 outline-none transition-colors data-[disabled]:pointer-events-none"
158+
type="button"
159+
onClick={() => {
160+
handleSelectPreset(preset.value)
161+
}}
163162
>
164-
<EllipseMiniSolid />
165-
</div>
166-
{preset.label}
167-
</button>
168-
</li>
169-
)
170-
})}
171-
<li>
172-
<button
173-
className="bg-ui-bg-base hover:bg-ui-bg-base-hover focus-visible:bg-ui-bg-base-pressed text-ui-fg-base data-[disabled]:text-ui-fg-disabled txt-compact-small relative flex w-full cursor-pointer select-none items-center rounded-md px-2 py-1.5 outline-none transition-colors data-[disabled]:pointer-events-none"
174-
type="button"
175-
onClick={handleSelectCustom}
176-
>
177-
<div
178-
className={clx(
179-
"transition-fg flex h-5 w-5 items-center justify-center",
180-
{
181-
"[&_svg]:invisible": !showCustom,
182-
}
183-
)}
163+
<div
164+
className={clx(
165+
"transition-fg flex h-5 w-5 items-center justify-center",
166+
{
167+
"[&_svg]:invisible": !isSelected,
168+
}
169+
)}
170+
>
171+
<EllipseMiniSolid />
172+
</div>
173+
{preset.label}
174+
</button>
175+
</li>
176+
)
177+
})}
178+
<li>
179+
<button
180+
className="bg-ui-bg-base hover:bg-ui-bg-base-hover focus-visible:bg-ui-bg-base-pressed text-ui-fg-base data-[disabled]:text-ui-fg-disabled txt-compact-small relative flex w-full cursor-pointer select-none items-center rounded-md px-2 py-1.5 outline-none transition-colors data-[disabled]:pointer-events-none"
181+
type="button"
182+
onClick={handleSelectCustom}
184183
>
185-
<EllipseMiniSolid />
186-
</div>
187-
{t("filters.date.custom")}
188-
</button>
189-
</li>
190-
</ul>
191-
{showCustom && (
192-
<div className="border-t px-1 pb-3 pt-1">
193-
<div>
194-
<div className="px-2 py-1">
195-
<Text size="xsmall" leading="compact" weight="plus">
196-
{t("filters.date.from")}
197-
</Text>
198-
</div>
199-
<div className="px-2 py-1">
200-
<DatePicker
201-
maxValue={customEndValue}
202-
value={customStartValue}
203-
onChange={(d) => handleCustomDateChange(d, "start")}
204-
/>
205-
</div>
206-
</div>
207-
<div>
208-
<div className="px-2 py-1">
209-
<Text size="xsmall" leading="compact" weight="plus">
210-
{t("filters.date.to")}
211-
</Text>
184+
<div
185+
className={clx(
186+
"transition-fg flex h-5 w-5 items-center justify-center",
187+
{
188+
"[&_svg]:invisible": !showCustom,
189+
}
190+
)}
191+
>
192+
<EllipseMiniSolid />
193+
</div>
194+
{t("filters.date.custom")}
195+
</button>
196+
</li>
197+
</ul>
198+
{showCustom && (
199+
<div className="border-t px-1 pb-3 pt-1">
200+
<div>
201+
<div className="px-2 py-1">
202+
<Text size="xsmall" leading="compact" weight="plus">
203+
{t("filters.date.from")}
204+
</Text>
205+
</div>
206+
<div className="px-2 py-1">
207+
<DatePicker
208+
maxValue={customEndValue}
209+
value={customStartValue}
210+
onChange={(d) => handleCustomDateChange(d, "start")}
211+
/>
212+
</div>
212213
</div>
213-
<div className="px-2 py-1">
214-
<DatePicker
215-
minValue={customStartValue}
216-
value={customEndValue || undefined}
217-
onChange={(d) => {
218-
handleCustomDateChange(d, "end")
219-
}}
220-
/>
214+
<div>
215+
<div className="px-2 py-1">
216+
<Text size="xsmall" leading="compact" weight="plus">
217+
{t("filters.date.to")}
218+
</Text>
219+
</div>
220+
<div className="px-2 py-1">
221+
<DatePicker
222+
minValue={customStartValue}
223+
value={customEndValue || undefined}
224+
onChange={(d) => {
225+
handleCustomDateChange(d, "end")
226+
}}
227+
/>
228+
</div>
221229
</div>
222230
</div>
223-
</div>
224-
)}
225-
</Popover.Content>
226-
</Popover.Portal>
231+
)}
232+
</Popover.Content>
233+
</Popover.Portal>
234+
)}
227235
</Popover.Root>
228236
)
229237
}
230238

231239
type DateDisplayProps = {
232240
label: string
233241
value?: string
242+
readonly?: boolean
234243
onRemove: () => void
235244
}
236245

237-
const DateDisplay = ({ label, value, onRemove }: DateDisplayProps) => {
246+
const DateDisplay = ({
247+
label,
248+
value,
249+
readonly,
250+
onRemove,
251+
}: DateDisplayProps) => {
238252
const handleRemove = (e: MouseEvent<HTMLButtonElement>) => {
239253
e.stopPropagation()
240254
onRemove()
@@ -245,8 +259,10 @@ const DateDisplay = ({ label, value, onRemove }: DateDisplayProps) => {
245259
asChild
246260
className={clx(
247261
"bg-ui-bg-field transition-fg shadow-borders-base text-ui-fg-subtle flex cursor-pointer select-none items-center rounded-md",
248-
"hover:bg-ui-bg-field-hover",
249-
"data-[state=open]:bg-ui-bg-field-hover"
262+
{
263+
"hover:bg-ui-bg-field-hover": !readonly,
264+
"data-[state=open]:bg-ui-bg-field-hover": !readonly,
265+
}
250266
)}
251267
>
252268
<div>
@@ -268,7 +284,7 @@ const DateDisplay = ({ label, value, onRemove }: DateDisplayProps) => {
268284
</div>
269285
</div>
270286
)}
271-
{value && (
287+
{!readonly && value && (
272288
<div>
273289
<button
274290
onClick={handleRemove}

0 commit comments

Comments
 (0)