fix signin, apply, and other
All checks were successful
ci / docker_image (push) Successful in 2m41s
ci / deploy (push) Successful in 24s

This commit is contained in:
Drake Marino 2025-06-19 22:12:51 -05:00
parent c4567270b5
commit eebd44faf8
6 changed files with 173 additions and 145 deletions

View File

@ -21,5 +21,5 @@ export function setJWT(cookies: Cookies, user: User) {
const maxAge = 60 * 60 * 24 * 30; // 30 days const maxAge = 60 * 60 * 24 * 30; // 30 days
const JWT = jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '30d' }); const JWT = jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '30d' });
cookies.set('jwt', JWT, { maxAge, path: '/', httpOnly: secure, secure: secure }); cookies.set('jwt', JWT, { maxAge, path: '/', httpOnly: false, secure: secure });
} }

View File

@ -147,8 +147,9 @@
> >
{/if} {/if}
<a <a
class="hover-bg-color block h-min p-1 pr-2 align-top" class="hover-bg-color block h-min p-1 px-2 align-top"
href={userState.id !== null ? '/account' : '/signin'} href={userState.id !== null ? '/account' : '/signin'}
onclick={toggleMenu}
> >
<span class="material-symbols-outlined h-min align-top"> <span class="material-symbols-outlined h-min align-top">
{userState.id !== null ? 'account_circle' : 'login'} {userState.id !== null ? 'account_circle' : 'login'}
@ -170,38 +171,36 @@
: 'block'} h-min w-full justify-between p-2 text-center" : 'block'} h-min w-full justify-between p-2 text-center"
> >
<div class="{largeScreen.current ? 'inline-block' : 'block'} text-left align-top"> <div class="{largeScreen.current ? 'inline-block' : 'block'} text-left align-top">
<!--{#if largeScreen.current}--> {#if largeScreen.current}
<div class="inline-block pr-3"> <div class="inline-block pr-3">
<p class="font-semibold">Drake Marino:</p> <p class="font-semibold">Drake Marino:</p>
<a class="hyperlink-color hyperlink-underline" href="mailto:drake@marinodev.com" <a class="hyperlink-color hyperlink-underline" href="mailto:drake@marinodev.com"
>drake@marinodev.com</a >drake@marinodev.com</a
> >
</div> </div>
<div class="inline-block"> <div class="inline-block">
<p class="font-semibold">Chetan Malkan:</p> <p class="font-semibold">Chetan Malkan:</p>
<a class="hyperlink-color hyperlink-underline" href="mailto:chetan@marinodev.com" <a class="hyperlink-color hyperlink-underline" href="mailto:chetan@marinodev.com"
>chetan@marinodev.com</a >chetan@marinodev.com</a
> >
</div> </div>
<!--{/if}--> {/if}
</div> </div>
{#if largeScreen.current} <!--{#if largeScreen.current}-->
<div <div class="{largeScreen.current ? 'inline-block' : 'block'} align-top font-semibold">
class="{largeScreen.current ? 'inline-block' : 'block text-left'} align-top font-semibold" <div class="font-semibold">MarinoDev</div>
> <div class="font-normal">2025</div>
<div class="font-semibold">MarinoDev</div> </div>
<div class="font-normal">2025</div> <!--{/if}-->
</div>
{/if}
<div class="{largeScreen.current ? 'inline-block text-right' : 'block text-left'} align-top"> <div class="{largeScreen.current ? 'inline-block text-right' : 'block text-left'} align-top">
<!--{#if largeScreen.current}--> {#if largeScreen.current}
<div class="font-semibold">Source Code:</div> <div class="font-semibold">Source Code:</div>
<a <a
class="hyperlink-color hyperlink-underline" class="hyperlink-color hyperlink-underline"
href="https://git.marinodev.com/MarinoDev/FBLA25" href="https://git.marinodev.com/MarinoDev/FBLA25"
>https://git.marinodev.com/MarinoDev/FBLA25</a >https://git.marinodev.com/MarinoDev/FBLA25</a
> >
<!--{/if}--> {/if}
</div> </div>
</footer> </footer>
</div> </div>

View File

@ -144,9 +144,9 @@
</script> </script>
<div class="base-container"> <div class="base-container">
<div class="content flex py-4"> <div class="content my-2 flex">
{#if largeScreen.current} {#if largeScreen.current}
<div class="elevated separator-borders m-2 inline-block h-min min-w-max rounded align-top"> <div class="elevated separator-borders mr-2 inline-block h-min min-w-max rounded align-top">
<div class="inline-block p-4"> <div class="inline-block p-4">
<img <img
alt="User avatar" alt="User avatar"
@ -188,7 +188,7 @@
</div> </div>
{/if} {/if}
<div class="inline-block w-full"> <div class="inline-block w-full">
<div class="elevated separator-borders m-2 h-min w-full rounded"> <div class="elevated separator-borders h-min w-full rounded">
<div class="bottom-border flex place-content-between"> <div class="bottom-border flex place-content-between">
<div class="p-3 font-semibold">User Details</div> <div class="p-3 font-semibold">User Details</div>
<div class="flex"> <div class="flex">
@ -204,6 +204,12 @@
<div class="font-semibold"> <div class="font-semibold">
ID: <span class="font-normal">{data.user.id}</span> ID: <span class="font-normal">{data.user.id}</span>
</div> </div>
<div class="font-semibold">
Username: <span class="font-normal">{data.user.username}</span>
</div>
<div class="font-semibold">
Full Name: <span class="font-normal">{data.user.fullName}</span>
</div>
<div class="font-semibold"> <div class="font-semibold">
Account active: <span class="material-symbols-outlined align-middle" Account active: <span class="material-symbols-outlined align-middle"
>{data.user.active ? 'check' : 'cancel'}</span >{data.user.active ? 'check' : 'cancel'}</span
@ -214,11 +220,11 @@
>{data.user.lastSignIn?.toLocaleDateString('en-US', dateFormatOptions)}</span >{data.user.lastSignIn?.toLocaleDateString('en-US', dateFormatOptions)}</span
> >
</div> </div>
{#if !data.user.company?.id} <!--{#if !data.user.company?.id}-->
<div class="pb-2 font-semibold"> <!-- <div class="pb-2 font-semibold">-->
Employer company: <span class="font-normal">N/A</span> <!-- Employer company: <span class="font-normal">N/A</span>-->
</div> <!-- </div>-->
{/if} <!--{/if}-->
{#if data.user.company?.id} {#if data.user.company?.id}
<div class="font-semibold"> <div class="font-semibold">
Employer company: Employer company:
@ -251,7 +257,7 @@
><span class="material-symbols-outlined align-middle">upload</span> Upload new version ><span class="material-symbols-outlined align-middle">upload</span> Upload new version
</button> </button>
{:else} {:else}
<div class="">No résumé submitted.</div> <!-- <div class="">No résumé submitted.</div>-->
<button class="dull-primary-bg-color mb-1 rounded-md px-2.5 py-1" onclick={openUpload} <button class="dull-primary-bg-color mb-1 rounded-md px-2.5 py-1" onclick={openUpload}
><span class="material-symbols-outlined align-middle">upload</span> Upload ><span class="material-symbols-outlined align-middle">upload</span> Upload
</button> </button>
@ -263,7 +269,7 @@
</div> </div>
</div> </div>
{#if data.applications} {#if data.applications}
<div class="elevated separator-borders m-2 inline-block h-min w-full rounded"> <div class="elevated separator-borders m-2 ml-0 inline-block h-min w-full rounded">
<div class="p-3 font-semibold">Pending applications</div> <div class="p-3 font-semibold">Pending applications</div>
{#each data.applications as application} {#each data.applications as application}
<button class="top-border accordion flex justify-between p-2"> <button class="top-border accordion flex justify-between p-2">

View File

@ -50,7 +50,7 @@
> >
{/if} {/if}
</div> </div>
<div class="scrollbar-on-elevated details-height overflow-y-scroll"> <div class="scrollbar-on-elevated overflow-y-scroll">
<h2 class="pt-2 font-semibold">Contact</h2> <h2 class="pt-2 font-semibold">Contact</h2>
<p>{data.posting.employer?.fullName} ({data.posting.employer?.username})</p> <p>{data.posting.employer?.fullName} ({data.posting.employer?.username})</p>
<a class="hover-hyperlink block" href="mailto:{data.posting.employer?.email}" <a class="hover-hyperlink block" href="mailto:{data.posting.employer?.email}"

View File

@ -3,6 +3,7 @@
import type { PageProps } from './$types'; import type { PageProps } from './$types';
import { employmentTypeDisplayName } from '$lib/shared.svelte'; import { employmentTypeDisplayName } from '$lib/shared.svelte';
import type { Posting } from '$lib/types'; import type { Posting } from '$lib/types';
import { MediaQuery } from 'svelte/reactivity';
const dateFormatOptions: Intl.DateTimeFormatOptions = { const dateFormatOptions: Intl.DateTimeFormatOptions = {
year: 'numeric', year: 'numeric',
@ -15,72 +16,89 @@
`https://ui-avatars.com/api/?background=random&format=svg&name=${encodeURIComponent(posting.company.name || 'COMPANY')}`; `https://ui-avatars.com/api/?background=random&format=svg&name=${encodeURIComponent(posting.company.name || 'COMPANY')}`;
} }
const largeScreen = new MediaQuery('min-width: 1024px');
let { data, form }: PageProps = $props(); let { data, form }: PageProps = $props();
</script> </script>
<div class="base-container"> {#snippet jobDetails()}
<div class="content flex"> <div
<div class="elevated separator-borders ml-4 mt-4 inline-block h-min w-1/2 rounded p-4"> class="elevated separator-borders my-2 h-min rounded p-4 {largeScreen.current
<div class="bottom-border elevated-bg flex justify-between pb-2"> ? 'mr-2 inline-block w-1/2'
<div class="inline-block"> : 'block w-full'}"
<img >
alt="Company Logo" <div class="bottom-border elevated-bg flex justify-between pb-2">
class="inline-block rounded" <div class="inline-block">
height="64" <img
onerror={(e) => logoFallback(e, data.posting)} alt="Company Logo"
src="/uploads/logos/{data.posting?.company.id}.jpg" class="inline-block rounded"
width="64" height="64"
/> onerror={(e) => logoFallback(e, data.posting)}
<div class="inline-block pl-2 align-top"> src="/uploads/logos/{data.posting?.company.id}.jpg"
<h1>{data.posting.title}</h1> width="64"
<h2>Company: {data.posting.company.name}</h2> />
</div> <div class="inline-block pl-2 align-top">
<h1>{data.posting.title}</h1>
<h2>Company: {data.posting.company.name}</h2>
</div> </div>
</div> </div>
<div class="scrollbar-on-elevated details-height overflow-y-scroll">
<h2 class="pt-2 font-semibold">Contact</h2>
<p>{data.posting.employer?.fullName} ({data.posting.employer?.username})</p>
<a class="hover-hyperlink" href="mailto:{data.posting.employer?.email}"
>{data.posting.employer?.email}</a
>
<a class="hover-hyperlink" href="tel:{data.posting.employer?.phone}"
>{data.posting.employer?.phone}</a
>
<h2 class="pt-2 font-semibold">Details</h2>
{#if data.posting.employmentType}
<p>{employmentTypeDisplayName(data.posting.employmentType)}</p>
{/if}
{#if data.posting.address}
<a
href="https://www.google.com/maps/search/?api=1&query={data.posting.address}"
class="block w-max"
>Address: <span class="hover-hyperlink">{data.posting.address}</span></a
>
{/if}
{#if data.posting.wage}
<p>Wage: {data.posting.wage}</p>
{/if}
{#if data.posting.createdAt}
<p>Posted: {data.posting.createdAt.toLocaleDateString('en-US', dateFormatOptions)}</p>
{/if}
{#if data.posting.link}
<a href={data.posting.link} class="block w-max"
>More information: <span class="hyperlink-color hyperlink-underline"
>{data.posting.link}</span
></a
>
{/if}
{#if data.posting.flyerLink}
<a href={data.posting.flyerLink} class="block w-max"
>Flyer: <span class="hyperlink-color hyperlink-underline">{data.posting.flyerLink}</span
></a
>
{/if}
<h2 class="pt-2 font-semibold">Job Description</h2>
<p class="whitespace-pre-wrap">{data.posting.description}</p>
</div>
</div> </div>
<div class="elevated separator-borders m-4 inline-block h-min w-1/2 rounded"> <div class="scrollbar-on-elevated overflow-y-scroll">
<h2 class="pt-2 font-semibold">Contact</h2>
<p>{data.posting.employer?.fullName} ({data.posting.employer?.username})</p>
<a class="hover-hyperlink" href="mailto:{data.posting.employer?.email}"
>{data.posting.employer?.email}</a
>
<a class="hover-hyperlink" href="tel:{data.posting.employer?.phone}"
>{data.posting.employer?.phone}</a
>
<h2 class="pt-2 font-semibold">Details</h2>
{#if data.posting.employmentType}
<p>{employmentTypeDisplayName(data.posting.employmentType)}</p>
{/if}
{#if data.posting.address}
<a
href="https://www.google.com/maps/search/?api=1&query={data.posting.address}"
class="block"
>Address: <span class="hover-hyperlink break-words">{data.posting.address}</span></a
>
{/if}
{#if data.posting.wage}
<p>Wage: {data.posting.wage}</p>
{/if}
{#if data.posting.createdAt}
<p>Posted: {data.posting.createdAt.toLocaleDateString('en-US', dateFormatOptions)}</p>
{/if}
{#if data.posting.link}
<a href={data.posting.link} class="block"
>More information: <span class="hyperlink-color hyperlink-underline break-all"
>{data.posting.link}</span
></a
>
{/if}
{#if data.posting.flyerLink}
<a href={data.posting.flyerLink} class="block"
>Flyer: <span class="hyperlink-color hyperlink-underline break-all"
>{data.posting.flyerLink}</span
></a
>
{/if}
<h2 class="pt-2 font-semibold">Job Description</h2>
<p class="whitespace-pre-wrap break-words">{data.posting.description}</p>
</div>
</div>
{/snippet}
<div class="base-container">
<div class="content {largeScreen.current ? 'flex' : 'block'}">
{#if largeScreen.current}
{@render jobDetails()}
{/if}
<div
class="elevated separator-borders my-2 h-min rounded {largeScreen.current
? 'inline-block w-1/2'
: 'block w-full'}"
>
<div class="bottom-border flex place-content-between"> <div class="bottom-border flex place-content-between">
<div class="p-3 font-semibold">Apply</div> <div class="p-3 font-semibold">Apply</div>
</div> </div>
@ -113,5 +131,8 @@
</button> </button>
</form> </form>
</div> </div>
{#if !largeScreen.current}
{@render jobDetails()}
{/if}
</div> </div>
</div> </div>

View File

@ -28,53 +28,55 @@
let { data, form }: PageProps = $props(); let { data, form }: PageProps = $props();
</script> </script>
<div class="signin-container place-items-center pt-8"> <div class="signin-container">
<div class="separator-borders elevated content rounded-md p-8"> <div class="content my-2">
<h1 class="text-weight-semibold mb-4 text-center">Welcome Back!</h1> <div class="separator-borders elevated rounded-md px-2 py-8">
<form class="arrange-vertically" method="POST" use:enhance> <h1 class="text-weight-semibold mb-4 text-center">Welcome Back!</h1>
<div class="bg-color my-2 rounded"> <form class="arrange-vertically" method="POST" use:enhance>
<input <div class="bg-color my-2 rounded">
class="input-field w-full"
name="username"
placeholder="Username"
required
type="text"
/>
</div>
<div class="relative w-full">
<div class="bg-color mt-4 rounded">
<input <input
class="input-field w-full pr-10" class="input-field w-full"
name="password" name="username"
placeholder="Password" placeholder="Username"
required required
type={passwordVisible ? 'text' : 'password'} type="text"
/> />
</div> </div>
<button <div class="relative w-full">
class="absolute right-2.5 top-6 -translate-y-1/2 transform" <div class="bg-color mt-4 rounded">
onclick={showPassword} <input
type="button" class="input-field w-full pr-10"
> name="password"
<span class="material-symbols-outlined" placeholder="Password"
>{passwordVisible ? 'visibility' : 'visibility_off'}</span required
type={passwordVisible ? 'text' : 'password'}
/>
</div>
<button
class="absolute right-2.5 top-6 -translate-y-1/2 transform"
onclick={showPassword}
type="button"
> >
<span class="material-symbols-outlined"
>{passwordVisible ? 'visibility' : 'visibility_off'}</span
>
</button>
</div>
{#if form?.errorMessage}
<div class="my-2 text-red-500">{form.errorMessage}</div>
{/if}
<button
class="primary-bg-color mt-8 w-full rounded px-2 py-2"
formaction="?/signin"
type="submit"
>Sign In
</button> </button>
</div> <a class="low-emphasis-text-button mt-2" href="/register"
>Don't have an account? Register here.</a
{#if form?.errorMessage} >
<div class="my-2 text-red-500">{form.errorMessage}</div> </form>
{/if} </div>
<button
class="primary-bg-color mt-8 w-full rounded px-2 py-2"
formaction="?/signin"
type="submit"
>Sign In
</button>
<a class="low-emphasis-text-button mt-2" href="/register"
>Don't have an account? Register here.</a
>
</form>
</div> </div>
</div> </div>