dev
All checks were successful
ci / docker_image (push) Successful in 1m37s
ci / deploy (push) Successful in 16s

This commit is contained in:
Drake Marino 2025-01-31 18:51:20 -06:00
parent 5eca1635f5
commit 2acc65823b
15 changed files with 162 additions and 113 deletions

View File

@ -306,7 +306,7 @@ export async function deleteCompany(id: number): Promise<void> {
export async function getCompany(id: number): Promise<Company> { export async function getCompany(id: number): Promise<Company> {
const [company] = await sql` const [company] = await sql`
SELECT id, name, description, website, created_at AS "createdAt" SELECT id, name, description, website, created_at AS "createdAt", company_code AS "companyCode"
FROM companies FROM companies
WHERE id = ${id}; WHERE id = ${id};
`; `;
@ -750,3 +750,12 @@ export async function getApplications(postingId: number): Promise<Application[]>
return <Application[]>(<unknown>data); return <Application[]>(<unknown>data);
} }
export async function setUserCompanyId(userId: number, companyId: number): Promise<void> {
await sql`
UPDATE users
SET company_id = ${companyId},
company_code = (SELECT company_code FROM companies WHERE id = ${companyId})
WHERE id = ${userId};
`;
}

View File

@ -119,7 +119,7 @@
{#if data.user.company?.id} {#if data.user.company?.id}
<div class="font-semibold"> <div class="font-semibold">
Employer company: Employer company:
<div class="top-border mt-2 p-3"> <div class="top-border mt-2 p-3 align-top">
<img <img
id="logo" id="logo"
class="mb-2 inline-block rounded" class="mb-2 inline-block rounded"
@ -129,7 +129,7 @@
height="32" height="32"
width="32" width="32"
/> />
<div class="inline-block"> <div class="inline-block pl-2 align-top">
<div>{data.user.company.name}</div> <div>{data.user.company.name}</div>
<div class="max-char-length font-normal">{data.user.company.description}</div> <div class="max-char-length font-normal">{data.user.company.description}</div>
</div> </div>

View File

@ -147,7 +147,7 @@
id="phone" id="phone"
placeholder="Phone" placeholder="Phone"
class="w-full rounded font-normal" class="w-full rounded font-normal"
pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}" pattern="([0-9]\{3}) [0-9]\{3}-[0-9]\{3}"
/> />
</div> </div>
<div class="mt-4 text-sm font-semibold"> <div class="mt-4 text-sm font-semibold">

View File

@ -1,6 +1,8 @@
<script lang="ts"> <script lang="ts">
import type { PageProps } from './$types'; import type { PageProps } from './$types';
import type { Company, User } from '$lib/types'; import type { Company } from '$lib/types';
import { userState } from '$lib/shared.svelte';
import { PERMISSIONS } from '$lib/consts';
function logoFallback(e: Event, company: Company) { function logoFallback(e: Event, company: Company) {
(e.target as HTMLImageElement).src = (e.target as HTMLImageElement).src =
@ -13,7 +15,15 @@
<div class="base-container-small"> <div class="base-container-small">
<div class="content"> <div class="content">
<div class="elevated separator-borders mb-4 mt-4 rounded"> <div class="elevated separator-borders mb-4 mt-4 rounded">
<div class="p-3 font-semibold">Companies</div> <div class="flex justify-between">
<div class="inline-block p-3 font-semibold">Companies</div>
{#if (userState.perms & PERMISSIONS.MANAGE_COMPANIES) > 0 || (userState.perms & PERMISSIONS.SUBMIT_POSTINGS) > 0}
<a
class="dull-primary-bg-color m-2 inline-block rounded-md px-2.5 py-1"
href="/companies/create">Create new company</a
>
{/if}
</div>
{#each data.companies as company} {#each data.companies as company}
<a class="top-border hover-bg-color inline-block w-full p-3" href="/companies/{company.id}"> <a class="top-border hover-bg-color inline-block w-full p-3" href="/companies/{company.id}">
<img <img

View File

@ -27,9 +27,8 @@ export const actions: Actions = {
const requestPerms = getUserPerms(cookies); const requestPerms = getUserPerms(cookies);
if ( if (
!( !(
requestPerms >= 0 && (requestPerms >= 0 && (requestPerms & PERMISSIONS.MANAGE_COMPANIES) > 0) ||
((requestPerms & PERMISSIONS.MANAGE_COMPANIES) > 0 || (requestPerms & PERMISSIONS.SUBMIT_POSTINGS) > 0
((requestPerms & PERMISSIONS.SUBMIT_POSTINGS) > 0 && getUserCompanyId(cookies) === id))
) )
) { ) {
return fail(403, { errorMessage: 'You cannot preform this action!' }); return fail(403, { errorMessage: 'You cannot preform this action!' });

View File

@ -10,11 +10,30 @@
document.getElementById('deleteConfirmModal')!.style.display = 'none'; document.getElementById('deleteConfirmModal')!.style.display = 'none';
} }
function logoFallback(e: Event) {
(e.target as HTMLImageElement).src =
`https://ui-avatars.com/api/?background=random&format=svg&name=${encodeURIComponent(data.company.name!)}`;
}
let { data, form }: PageProps = $props(); let { data, form }: PageProps = $props();
</script> </script>
<div class="base-container"> <div class="base-container">
<div class="content"> <div class="content">
<div class="m-4">
<img
class="mb-2 inline-block rounded-lg"
src="/uploads/logos/{data.company.id}.svg?timestamp=${Date.now()}"
alt="User avatar"
onerror={logoFallback}
height="80"
width="80"
/>
<div class="inline-block pl-4 align-top">
<h1 class="font-bold">{data.company.name}</h1>
<h2>Company code: <span class="font-semibold">{data.company.companyCode}</span></h2>
</div>
</div>
<div class="elevated separator-borders m-4 rounded"> <div class="elevated separator-borders m-4 rounded">
<div class="bottom-border flex place-content-between"> <div class="bottom-border flex place-content-between">
<div class="p-3 font-semibold">Edit Company {data.company.name}</div> <div class="p-3 font-semibold">Edit Company {data.company.name}</div>

View File

@ -14,9 +14,8 @@ export const actions: Actions = {
const requestPerms = getUserPerms(cookies); const requestPerms = getUserPerms(cookies);
if ( if (
!( !(
requestPerms >= 0 && (requestPerms >= 0 && (requestPerms & PERMISSIONS.MANAGE_COMPANIES) > 0) ||
((requestPerms & PERMISSIONS.MANAGE_COMPANIES) > 0 || (requestPerms & PERMISSIONS.SUBMIT_POSTINGS) > 0
((requestPerms & PERMISSIONS.SUBMIT_POSTINGS) > 0 && getUserCompanyId(cookies)))
) )
) { ) {
return fail(403, { errorMessage: 'You cannot preform this action!' }); return fail(403, { errorMessage: 'You cannot preform this action!' });

View File

@ -14,10 +14,10 @@
access to create job postings. access to create job postings.
</p> </p>
<p> <p>
If you are your company admin, first create your account (without inputting a code). Then, go If you are your company admin, first create your account (without inputting a code). Reach out
to the company page, and use the button in the top right to create a new company. Once created to a CareerConnect admin to elevate your account privaleges. Then, go to the company page, and
and approved by a CareerConnect admin, you will be able to see the company code, which you can use the button in the top right to create a new company. Once created, you will be able to see
then give to your employees. the company code, which you can then give to your employees.
</p> </p>
</div> </div>
</div> </div>

View File

@ -36,7 +36,16 @@
</script> </script>
<div class="base-container"> <div class="base-container">
<div class="content flex"> <div class="content">
<div class="bottom-border mb-4 flex justify-between pb-2">
<h1 class="inline-block p-2">Postings</h1>
{#if userState.companyId && (userState.perms & PERMISSIONS.SUBMIT_POSTINGS) > 0}
<a class="dull-primary-bg-color m-2 h-min rounded-md px-2.5 py-1" href="/postings/create"
>Create new posting</a
>
{/if}
</div>
<div class="flex">
<div class="right-border inline-block w-1/3"> <div class="right-border inline-block w-1/3">
{#each data.postings as posting} {#each data.postings as posting}
<button <button
@ -64,7 +73,7 @@
</div> </div>
{#if details !== undefined} {#if details !== undefined}
<div <div
class="elevated separator-borders top-with-navbar sticky ml-4 mt-4 inline-block h-min w-2/3 rounded p-4" class="elevated separator-borders top-with-navbar sticky ml-4 inline-block h-min w-2/3 rounded p-4"
> >
<div class="bottom-border flex justify-between pb-2"> <div class="bottom-border flex justify-between pb-2">
<div class="inline-block"> <div class="inline-block">
@ -109,7 +118,8 @@
{#if details.address} {#if details.address}
<a <a
href="https://www.google.com/maps/search/?api=1&query={details.address}" href="https://www.google.com/maps/search/?api=1&query={details.address}"
class="block w-max">Address: <span class="hover-hyperlink">{details.address}</span></a class="block w-max"
>Address: <span class="hover-hyperlink">{details.address}</span></a
> >
{/if} {/if}
{#if details.wage} {#if details.wage}
@ -137,4 +147,5 @@
</div> </div>
{/if} {/if}
</div> </div>
</div>
</div> </div>

View File

@ -36,7 +36,7 @@
<h2>Company: {data.posting.company.name}</h2> <h2>Company: {data.posting.company.name}</h2>
</div> </div>
</div> </div>
{#if userState.perms >= 0 && ((userState.perms & PERMISSIONS.MANAGE_POSTINGS) > 0 || ((userState.perms & PERMISSIONS.SUBMIT_POSTINGS) > 0 && userState.companyId === details.company.id))} {#if userState.perms >= 0 && ((userState.perms & PERMISSIONS.MANAGE_POSTINGS) > 0 || ((userState.perms & PERMISSIONS.SUBMIT_POSTINGS) > 0 && userState.companyId === data.posting.company.id))}
<a <a
class="dull-primary-bg-color inline-block h-min rounded-md px-2.5 py-1 align-top" class="dull-primary-bg-color inline-block h-min rounded-md px-2.5 py-1 align-top"
href="/postings/{data.posting.id}/manage">Manage posting</a href="/postings/{data.posting.id}/manage">Manage posting</a

View File

@ -14,7 +14,7 @@ export const load: PageServerLoad = async ({ params, cookies }) => {
if ( if (
perms >= 0 && perms >= 0 &&
((perms & PERMISSIONS.MANAGE_POSTINGS) > 0 || ((perms & PERMISSIONS.MANAGE_POSTINGS) > 0 ||
((perms & PERMISSIONS.SUBMIT_POSTINGS) > 0 && getUserCompanyId(cookies) === id)) ((perms & PERMISSIONS.SUBMIT_POSTINGS) > 0 && getUserCompanyId(cookies)))
) { ) {
return { return {
applications: await getApplications(id) applications: await getApplications(id)

View File

@ -78,7 +78,7 @@
<p>Email: {application.user.email}</p> <p>Email: {application.user.email}</p>
{/if} {/if}
{#if application.user?.phone} {#if application.user?.phone}
<p>Phone: {application.user.email}</p> <p>Phone: {application.user.phone}</p>
{/if} {/if}
{#if application.createdAt} {#if application.createdAt}
<p> <p>

View File

@ -9,10 +9,11 @@ export const load: PageServerLoad = async ({ cookies, params }) => {
const id = parseInt(params.posting); const id = parseInt(params.posting);
const perms = getUserPerms(cookies); const perms = getUserPerms(cookies);
// TODO check if user is allowed to edit this posting
if ( if (
perms >= 0 && perms >= 0 &&
((perms & PERMISSIONS.MANAGE_POSTINGS) > 0 || ((perms & PERMISSIONS.MANAGE_POSTINGS) > 0 ||
((perms & PERMISSIONS.SUBMIT_POSTINGS) > 0 && getUserCompanyId(cookies) === id)) ((perms & PERMISSIONS.SUBMIT_POSTINGS) > 0 && getUserCompanyId(cookies)))
) { ) {
return { return {
posting: await getPosting(id) posting: await getPosting(id)

View File

@ -47,7 +47,8 @@ export const actions: Actions = {
active: true, active: true,
email: email, email: email,
phone: phone, phone: phone,
fullName: fullName fullName: fullName,
companyCode: companyCode
}; };
if (password === confirmPassword) { if (password === confirmPassword) {
try { try {

View File

@ -83,7 +83,7 @@
id="phone" id="phone"
placeholder="Phone" placeholder="Phone"
class="w-full rounded font-normal" class="w-full rounded font-normal"
pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}" pattern="([0-9]\{3}) [0-9]\{3}-[0-9]\{3}"
/> />
</div> </div>
<div class="relative mt-4 text-sm font-semibold"> <div class="relative mt-4 text-sm font-semibold">