125 lines
2.8 KiB
Svelte
125 lines
2.8 KiB
Svelte
<script lang="ts">
|
|
import { applicationStore, type Application } from '$lib/ApplicationsStore.svelte';
|
|
import { get } from '$lib/utils';
|
|
import { onMount } from 'svelte';
|
|
|
|
let filter = $state('');
|
|
|
|
onMount(() => {
|
|
applicationStore.loadAll();
|
|
});
|
|
|
|
let apps = $derived(
|
|
applicationStore.all.filter((i) => i.status_id === null && !i.linked_application)
|
|
);
|
|
|
|
let internal = $derived(
|
|
apps.filter((i) => {
|
|
if (!filter) {
|
|
return true;
|
|
}
|
|
const f = new RegExp(filter, 'ig');
|
|
|
|
let x = i.title;
|
|
|
|
if (i.company) {
|
|
x = `${x} @ ${i.company}`;
|
|
}
|
|
|
|
return x.match(f);
|
|
})
|
|
);
|
|
|
|
let gettingNext = $state(false);
|
|
|
|
async function getNext() {
|
|
gettingNext = true;
|
|
try {
|
|
const r: Application[] = await get('mail/getNext');
|
|
for (const app of r) {
|
|
applicationStore.all.push(app);
|
|
}
|
|
if (r.length > 0) {
|
|
applicationStore.loadItem = r[0];
|
|
}
|
|
} catch (e) {
|
|
console.error('TODO inform user', e);
|
|
} finally {
|
|
gettingNext = false;
|
|
}
|
|
}
|
|
|
|
function docKey(e: KeyboardEvent) {
|
|
if (e.ctrlKey && e.code === 'KeyJ' && internal.length > 0) {
|
|
applicationStore.loadItem = internal[0];
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
return;
|
|
}
|
|
}
|
|
|
|
$effect(() => {
|
|
document.addEventListener('keydown', docKey, false);
|
|
return () => {
|
|
document.removeEventListener('keydown', docKey);
|
|
};
|
|
});
|
|
</script>
|
|
|
|
<div class="w-2/12 card p-3 flex flex-col flex-shrink min-h-0">
|
|
<h1>To Apply</h1>
|
|
<div class="flex pb-2 items-center">
|
|
<input placeholder="Filter" class="p-2 flex-grow" bind:value={filter} />
|
|
<div>
|
|
{internal.length}
|
|
</div>
|
|
{#if !gettingNext}
|
|
<button class="p-2 text-violet-500" onclick={() => getNext()}>
|
|
<span class="bi bi-send-arrow-down"></span>
|
|
</button>
|
|
{:else}
|
|
<span class="bi bi-arrow-repeat animate-spin"></span>
|
|
{/if}
|
|
</div>
|
|
<div class="overflow-auto flex-grow p-2">
|
|
{#each internal as item}
|
|
<div
|
|
class="card p-2 my-2 bg-slate-100 max-w-full"
|
|
draggable="true"
|
|
ondragstart={() => applicationStore.dragStart(item)}
|
|
ondragend={() => {
|
|
window.requestAnimationFrame(() => {
|
|
applicationStore.dragEnd();
|
|
});
|
|
}}
|
|
role="none"
|
|
>
|
|
<div
|
|
class="max-w-full"
|
|
class:animate-pulse={applicationStore.dragging?.id === item.id}
|
|
>
|
|
<h2 class="text-lg text-blue-500 flex gap-2 max-w-full overflow-hidden">
|
|
<div class="flex-grow max-w-[90%]">
|
|
<div class="whitespace-nowrap overflow-hidden">
|
|
{item.title}
|
|
</div>
|
|
{#if item.company}
|
|
<div class="text-violet-800">
|
|
@ {item.company}
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
<div>
|
|
{#if item.url.includes('linkedin')}
|
|
<span class="bi bi-linkedin"></span>
|
|
{:else if item.url.includes('glassdoor')}
|
|
<span class="bi bi-eyeglasses"></span>
|
|
{/if}
|
|
</div>
|
|
</h2>
|
|
</div>
|
|
</div>
|
|
{/each}
|
|
</div>
|
|
</div>
|