Skip to content

Commit 726af49

Browse files
committed
feat(domain-submissions): allow filtering by status
1 parent 96444dc commit 726af49

File tree

7 files changed

+228
-30
lines changed

7 files changed

+228
-30
lines changed

src/lib/components/ui/select/index.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { Select as SelectPrimitive } from "bits-ui";
2+
3+
import Label from "./select-label.svelte";
4+
import Item from "./select-item.svelte";
5+
import Content from "./select-content.svelte";
6+
import Trigger from "./select-trigger.svelte";
7+
import Separator from "./select-separator.svelte";
8+
9+
const Root = SelectPrimitive.Root;
10+
const Group = SelectPrimitive.Group;
11+
const Input = SelectPrimitive.Input;
12+
const Value = SelectPrimitive.Value;
13+
14+
export {
15+
Root,
16+
Group,
17+
Input,
18+
Label,
19+
Item,
20+
Value,
21+
Content,
22+
Trigger,
23+
Separator,
24+
//
25+
Root as Select,
26+
Group as SelectGroup,
27+
Input as SelectInput,
28+
Label as SelectLabel,
29+
Item as SelectItem,
30+
Value as SelectValue,
31+
Content as SelectContent,
32+
Trigger as SelectTrigger,
33+
Separator as SelectSeparator,
34+
};
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<script lang="ts">
2+
import { Select as SelectPrimitive } from "bits-ui";
3+
import { scale } from "svelte/transition";
4+
import { cn, flyAndScale } from "$lib/utils.js";
5+
6+
type $$Props = SelectPrimitive.ContentProps;
7+
type $$Events = SelectPrimitive.ContentEvents;
8+
9+
export let sideOffset: $$Props["sideOffset"] = 4;
10+
export let inTransition: $$Props["inTransition"] = flyAndScale;
11+
export let inTransitionConfig: $$Props["inTransitionConfig"] = undefined;
12+
export let outTransition: $$Props["outTransition"] = scale;
13+
export let outTransitionConfig: $$Props["outTransitionConfig"] = {
14+
start: 0.95,
15+
opacity: 0,
16+
duration: 50,
17+
};
18+
19+
let className: $$Props["class"] = undefined;
20+
export { className as class };
21+
</script>
22+
23+
<SelectPrimitive.Content
24+
{inTransition}
25+
{inTransitionConfig}
26+
{outTransition}
27+
{outTransitionConfig}
28+
{sideOffset}
29+
class={cn(
30+
"bg-popover text-popover-foreground relative z-50 min-w-[8rem] overflow-hidden rounded-md border shadow-md outline-none",
31+
className
32+
)}
33+
{...$$restProps}
34+
on:keydown
35+
>
36+
<div class="w-full p-1">
37+
<slot />
38+
</div>
39+
</SelectPrimitive.Content>
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<script lang="ts">
2+
import Check from "lucide-svelte/icons/check";
3+
import { Select as SelectPrimitive } from "bits-ui";
4+
import { cn } from "$lib/utils.js";
5+
6+
type $$Props = SelectPrimitive.ItemProps;
7+
type $$Events = SelectPrimitive.ItemEvents;
8+
9+
let className: $$Props["class"] = undefined;
10+
export let value: $$Props["value"];
11+
export let label: $$Props["label"] = undefined;
12+
export let disabled: $$Props["disabled"] = undefined;
13+
export { className as class };
14+
</script>
15+
16+
<SelectPrimitive.Item
17+
{value}
18+
{disabled}
19+
{label}
20+
class={cn(
21+
"data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
22+
className
23+
)}
24+
{...$$restProps}
25+
on:click
26+
on:keydown
27+
on:focusin
28+
on:focusout
29+
on:pointerleave
30+
on:pointermove
31+
>
32+
<span class="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
33+
<SelectPrimitive.ItemIndicator>
34+
<Check class="h-4 w-4" />
35+
</SelectPrimitive.ItemIndicator>
36+
</span>
37+
<slot>
38+
{label || value}
39+
</slot>
40+
</SelectPrimitive.Item>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<script lang="ts">
2+
import { Select as SelectPrimitive } from "bits-ui";
3+
import { cn } from "$lib/utils.js";
4+
5+
type $$Props = SelectPrimitive.LabelProps;
6+
7+
let className: $$Props["class"] = undefined;
8+
export { className as class };
9+
</script>
10+
11+
<SelectPrimitive.Label
12+
class={cn("py-1.5 pl-8 pr-2 text-sm font-semibold", className)}
13+
{...$$restProps}
14+
>
15+
<slot />
16+
</SelectPrimitive.Label>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<script lang="ts">
2+
import { Select as SelectPrimitive } from "bits-ui";
3+
import { cn } from "$lib/utils.js";
4+
5+
type $$Props = SelectPrimitive.SeparatorProps;
6+
7+
let className: $$Props["class"] = undefined;
8+
export { className as class };
9+
</script>
10+
11+
<SelectPrimitive.Separator class={cn("bg-muted -mx-1 my-1 h-px", className)} {...$$restProps} />
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<script lang="ts">
2+
import { Select as SelectPrimitive } from "bits-ui";
3+
import ChevronDown from "lucide-svelte/icons/chevron-down";
4+
import { cn } from "$lib/utils.js";
5+
6+
type $$Props = SelectPrimitive.TriggerProps;
7+
type $$Events = SelectPrimitive.TriggerEvents;
8+
9+
let className: $$Props["class"] = undefined;
10+
export { className as class };
11+
</script>
12+
13+
<SelectPrimitive.Trigger
14+
class={cn(
15+
"border-input bg-background ring-offset-background focus-visible:ring-ring aria-[invalid]:border-destructive data-[placeholder]:[&>span]:text-muted-foreground flex h-10 w-full items-center justify-between rounded-md border px-3 py-2 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
16+
className
17+
)}
18+
{...$$restProps}
19+
let:builder
20+
on:click
21+
on:keydown
22+
>
23+
<slot {builder} />
24+
<div>
25+
<ChevronDown class="h-4 w-4 opacity-50" />
26+
</div>
27+
</SelectPrimitive.Trigger>

src/routes/(nosearch)/domain-submissions/+page.svelte

Lines changed: 61 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@
66
import RiArrowDropRightLine from '~icons/ri/arrow-drop-right-line';
77
import RiLinksLine from '~icons/ri/links-line';
88
import RiLoader2Line from '~icons/ri/loader-2-line';
9+
910
import type { SubmissionsResult } from './+page.server.js';
1011
import SignInButton from '@/components/custom/SignInButton.svelte';
12+
1113
import * as Card from '@/components/ui/card';
14+
import * as Select from '$lib/components/ui/select';
1215
1316
let { data } = $props();
1417
@@ -37,37 +40,45 @@
3740
clearTimeout(debounceTimer);
3841
debounceTimer = setTimeout(callback, ms);
3942
}
43+
44+
let filter = $state({
45+
status: { value: '', label: 'any' }
46+
});
4047
</script>
4148

42-
{#snippet submissions(submissions: SubmissionsResult)}
43-
<ul class="grid w-fit grid-cols-[16rem,1fr,1fr] gap-2 pr-16">
44-
{#each submissions.items as item}
45-
<li class="contents">
46-
<div class="grid grid-cols-[7rem,1fr] gap-x-2">
47-
<div
48-
class={`col-span-2 flex flex-col justify-center rounded-2xl p-2 px-4 text-black ${item.status == 'APPROVED' ? ' bg-green-300' : item.status == 'REJECTED' ? ' !col-span-1 bg-red-300' : ' bg-gray-300'}`}
49-
>
50-
{item.status}
51-
</div>
52-
{#if item.status == 'REJECTED'}
53-
<div class="mr-2 flex flex-col">
54-
<div>reason: {item.rejection_reason}</div>
55-
{#if item.rejection_detail}
56-
<div>detail: {item.rejection_detail}</div>
57-
{/if}
49+
{#snippet submissions(items: SubmissionsResult['items'])}
50+
{#if items.length > 0}
51+
<ul class="grid w-fit grid-cols-[16rem,1fr,1fr] gap-2 pr-16">
52+
{#each items as item}
53+
<li class="contents">
54+
<div class="grid grid-cols-[7rem,1fr] gap-x-2">
55+
<div
56+
class={`col-span-2 flex flex-col justify-center rounded-2xl p-2 px-4 text-black ${item.status == 'APPROVED' ? ' bg-green-300' : item.status == 'REJECTED' ? ' !col-span-1 bg-red-300' : ' bg-gray-300'}`}
57+
>
58+
{item.status}
5859
</div>
59-
{/if}
60-
</div>
61-
<div class="flex flex-row items-center gap-2 pr-4">
62-
<span>{item.name}</span>
63-
</div>
64-
<div class="flex flex-row items-center gap-2">
65-
{new Date(item.submitted_on).toISOString().slice(0, 10)},
66-
{new Date(item.submitted_on).toISOString().slice(11, 16)} (UTC)
67-
</div>
68-
</li>
69-
{/each}
70-
</ul>
60+
{#if item.status == 'REJECTED'}
61+
<div class="mr-2 flex flex-col">
62+
<div>reason: {item.rejection_reason}</div>
63+
{#if item.rejection_detail}
64+
<div>detail: {item.rejection_detail}</div>
65+
{/if}
66+
</div>
67+
{/if}
68+
</div>
69+
<div class="flex flex-row items-center gap-2 pr-4">
70+
<span>{item.name}</span>
71+
</div>
72+
<div class="flex flex-row items-center gap-2">
73+
{new Date(item.submitted_on).toISOString().slice(0, 10)},
74+
{new Date(item.submitted_on).toISOString().slice(11, 16)} (UTC)
75+
</div>
76+
</li>
77+
{/each}
78+
</ul>
79+
{:else}
80+
Nothing on this page...
81+
{/if}
7182
{/snippet}
7283

7384
<main class="flex w-full max-w-4xl flex-col gap-2 self-center px-6">
@@ -102,7 +113,7 @@
102113
{#if domainInput.length > 0}
103114
{#if submissionsForInput.count > 0}
104115
<div class="mb-4">Found {submissionsForInput.count} pre-existing submission(s)</div>
105-
{@render submissions(submissionsForInput)}
116+
{@render submissions(submissionsForInput.items)}
106117
{:else}
107118
Found no pre-existing submission(s)
108119
{/if}
@@ -131,7 +142,27 @@
131142
{/await}
132143
</div>
133144
</div>
134-
{@render submissions(data.submissions)}
145+
<form class="mt-3 p-2">
146+
<h3 class="text-lg">Filter</h3>
147+
<label class="flex flex-row items-center gap-4">
148+
By Status <Select.Root bind:selected={filter.status}>
149+
<Select.Trigger class="w-[180px]">
150+
<Select.Value placeholder="any" />
151+
</Select.Trigger>
152+
<Select.Content>
153+
<Select.Item value="">any</Select.Item>
154+
<Select.Item value="APPROVED">APPROVED</Select.Item>
155+
<Select.Item value="REJECTED">REJECTED</Select.Item>
156+
<Select.Item value="PENDING">PENDING</Select.Item>
157+
</Select.Content>
158+
</Select.Root>
159+
</label>
160+
</form>
161+
{@render submissions(
162+
data.submissions.items.filter((item) =>
163+
filter.status.value !== '' ? item.status == filter.status.value : true
164+
)
165+
)}
135166
<div class="flex flex-row items-center justify-center gap-4 p-4">
136167
<Button
137168
href={data.page == 0 ? '' : `?page=${data.page - 1}`}

0 commit comments

Comments
 (0)