|
| 1 | +<script lang="ts"> |
| 2 | + import { enhance } from '$app/forms'; |
| 3 | + import Head from '$lib/components/Head.svelte'; |
| 4 | + import { projectStatuses } from '$lib/utils.js'; |
| 5 | + import { ExternalLink } from '@lucide/svelte'; |
| 6 | + import relativeDate from 'tiny-relative-date'; |
| 7 | +
|
| 8 | + let { data, form } = $props(); |
| 9 | +
|
| 10 | + let userSearch = $state(''); |
| 11 | +
|
| 12 | + let users = $derived(data.users); //form?.users ?? |
| 13 | +
|
| 14 | + let filteredProjects = $derived( |
| 15 | + data.users.filter((user) => |
| 16 | + user.name?.toLowerCase().includes(userSearch.toLowerCase()) |
| 17 | + ) |
| 18 | + ); |
| 19 | + let filteredUsers = $derived( |
| 20 | + data.users.filter((user) => user.name.toLowerCase().includes(userSearch.toLowerCase())) |
| 21 | + ); |
| 22 | +
|
| 23 | + let formPending = $state(false); |
| 24 | +</script> |
| 25 | + |
| 26 | +<Head title="Review" /> |
| 27 | + |
| 28 | +<div class="flex h-full flex-col"> |
| 29 | + <h1 class="mt-5 mb-3 font-hero text-3xl font-medium">Users</h1> |
| 30 | + |
| 31 | + <!--<div class="flex flex-col-reverse gap-5 lg:flex-row"> |
| 32 | + <div class="themed-box grow p-3"> |
| 33 | + <h2 class="mb-2 text-xl font-bold">Filter & Sort</h2> |
| 34 | + <form |
| 35 | + method="POST" |
| 36 | + use:enhance={() => { |
| 37 | + formPending = true; |
| 38 | + return async ({ update }) => { |
| 39 | + await update(); |
| 40 | + formPending = false; |
| 41 | + }; |
| 42 | + }} |
| 43 | + > |
| 44 | + <div class="grid grid-cols-1 gap-3 sm:grid-cols-2 md:grid-cols-3"> |
| 45 | + <!-- Project status --/> |
| 46 | + <label class="flex flex-col gap-1"> |
| 47 | + <span class="font-medium">Status</span> |
| 48 | + <select |
| 49 | + class="h-40 grow border-3 border-primary-700 bg-primary-900 fill-primary-50 p-2 text-sm ring-primary-900 placeholder:text-primary-900 active:ring-3" |
| 50 | + name="status" |
| 51 | + value={form?.fields.status ?? ['submitted']} |
| 52 | + multiple |
| 53 | + > |
| 54 | + <option value="building" class="truncate">Building</option> |
| 55 | + <option value="submitted" class="truncate">Submitted</option> |
| 56 | + <option value="t1_approved" class="truncate">Review approved</option> |
| 57 | + <option value="t2_approved" class="truncate">YSWS review approved</option> |
| 58 | + <option value="finalized" class="truncate">Finalized</option> |
| 59 | + <option value="rejected" class="truncate">Rejected</option> |
| 60 | + <option value="rejected_locked" class="truncate">Rejected (locked)</option> |
| 61 | + </select> |
| 62 | + </label> |
| 63 | +
|
| 64 | + <!-- Project --/> |
| 65 | + <label class="flex flex-col"> |
| 66 | + <span class="mb-1 font-medium">Project</span> |
| 67 | + <div class="flex h-40 flex-col"> |
| 68 | + <input |
| 69 | + type="text" |
| 70 | + placeholder="search" |
| 71 | + bind:value={projectSearch} |
| 72 | + class="themed-input-light border-b-0 py-1.5" |
| 73 | + /> |
| 74 | + <select |
| 75 | + class="themed-input-light grow" |
| 76 | + name="project" |
| 77 | + value={form?.fields.project ?? []} |
| 78 | + multiple |
| 79 | + > |
| 80 | + {#each filteredProjects as project} |
| 81 | + <option value={project.id} class="truncate">{project.name}</option> |
| 82 | + {/each} |
| 83 | + </select> |
| 84 | + </div> |
| 85 | + </label> |
| 86 | +
|
| 87 | + <!-- User --/> |
| 88 | + <label class="flex flex-col"> |
| 89 | + <span class="mb-1 font-medium">User</span> |
| 90 | + <div class="flex h-40 flex-col"> |
| 91 | + <input |
| 92 | + type="text" |
| 93 | + placeholder="search" |
| 94 | + bind:value={userSearch} |
| 95 | + class="themed-input-light border-b-0 py-1.5" |
| 96 | + /> |
| 97 | + <select |
| 98 | + class="themed-input-light grow" |
| 99 | + name="user" |
| 100 | + value={form?.fields.user ?? []} |
| 101 | + multiple |
| 102 | + > |
| 103 | + {#each filteredUsers as user} |
| 104 | + <option value={user?.id} class="truncate">{user?.name}</option> |
| 105 | + {/each} |
| 106 | + </select> |
| 107 | + </div> |
| 108 | + </label> |
| 109 | + </div> |
| 110 | + <button type="submit" class="button md primary mt-3 w-full" disabled={formPending}>Apply!</button> |
| 111 | + </form> |
| 112 | + </div> |
| 113 | + </div> |
| 114 | +
|
| 115 | + <h2 class="mt-4 mb-2 text-2xl font-bold">Filtered users</h2>--> |
| 116 | + |
| 117 | + {#if users.length == 0} |
| 118 | + <div class="flex grow items-center justify-center"> |
| 119 | + <div> |
| 120 | + <p class="themed-box p-3 shadow-lg/20"> |
| 121 | + No users found matching the filter <img |
| 122 | + src="https://emoji.slack-edge.com/T0266FRGM/heavysob/55bf09f6c9d93d08.png" |
| 123 | + alt="heavysob" |
| 124 | + class="inline h-5.5" |
| 125 | + /> |
| 126 | + </p> |
| 127 | + </div> |
| 128 | + </div> |
| 129 | + {:else} |
| 130 | + <div class="grid grid-cols-1 gap-4 lg:grid-cols-2 2xl:grid-cols-3"> |
| 131 | + {#each users as user} |
| 132 | + <div |
| 133 | + class="themed-box relative flex flex-col p-3 shadow-lg/20 transition-all hover:scale-102" |
| 134 | + > |
| 135 | + <a |
| 136 | + class="absolute inset-0 z-1" |
| 137 | + href={`/dashboard/admin/admin/users/${user.id}`} |
| 138 | + aria-label="project" |
| 139 | + > |
| 140 | + </a> |
| 141 | + <h1 class="flex flex-row gap-1 text-xl font-semibold"> |
| 142 | + <span class="grow truncate">{user.name}</span> |
| 143 | + </h1> |
| 144 | + <!-- <p class="text-sm"> |
| 145 | + by <a class="relative z-2 underline" href={`/dashboard/users/${project.user?.id}`} |
| 146 | + >{project.user?.name}</a |
| 147 | + > |
| 148 | + </p> |
| 149 | + <p class="grow">{project.project.description}</p> |
| 150 | + {#if project.project.url && project.project.url.length > 0} |
| 151 | + <div class="my-2 flex"> |
| 152 | + <a class="button sm primary relative z-2" href={project.project.url} target="_blank"> |
| 153 | + <ExternalLink /> |
| 154 | + Link to project |
| 155 | + </a> |
| 156 | + </div> |
| 157 | + {:else} |
| 158 | + <div class="mb-2"></div> |
| 159 | + {/if} |
| 160 | + <p class="text-sm"> |
| 161 | + {project.devlogCount} journal{project.devlogCount !== 1 ? 's' : ''} ∙ {Math.floor( |
| 162 | + project.timeSpent / 60 |
| 163 | + )}h {project.timeSpent % 60}min |
| 164 | + </p> |
| 165 | + <div class="flex flex-row gap-4"> |
| 166 | + <p class="grow text-sm"> |
| 167 | + Created <abbr |
| 168 | + title={`${project.project.createdAt.toUTCString()}`} |
| 169 | + class="relative z-2" |
| 170 | + > |
| 171 | + {relativeDate(project.project.createdAt)} |
| 172 | + </abbr> |
| 173 | + </p> |
| 174 | + <p class="text-sm">{projectStatuses[project.project.status]}</p> |
| 175 | + </div> --> |
| 176 | + </div> |
| 177 | + {/each} |
| 178 | + </div> |
| 179 | + {/if} |
| 180 | +</div> |
0 commit comments