diff --git a/src/app.css b/src/app.css index 13968d5..43e2536 100644 --- a/src/app.css +++ b/src/app.css @@ -318,11 +318,6 @@ h2 { @apply text-2xl } -/*.tooltip {*/ -/* position: relative;*/ -/* display: inline-block;*/ -/*}*/ - /* Tooltip text */ .tooltip-text { visibility: hidden; diff --git a/src/lib/db/index.server.ts b/src/lib/db/index.server.ts index fe381d7..106d65b 100644 --- a/src/lib/db/index.server.ts +++ b/src/lib/db/index.server.ts @@ -1,7 +1,7 @@ import bcrypt from 'bcrypt'; import sql from '$lib/db/db.server'; import { error } from '@sveltejs/kit'; -import { saveAvatar } from '$lib/index.server'; +import { saveAvatar, saveLogo } from '$lib/index.server'; import { EmploymentType, type User, @@ -281,6 +281,8 @@ export async function createCompany(company: Company): Promise { RETURNING id; `; + await saveLogo(company); + return response[0].id; } @@ -616,7 +618,7 @@ export async function getPosting(id: number): Promise { return posting; } -export async function getPostingFullData(id: number): Promise { +export async function getPostingWithCompanyUser(id: number): Promise { const data = await sql` WITH company_data AS ( SELECT @@ -715,15 +717,36 @@ export async function deleteApplicationWithUser( } export async function getApplications(postingId: number): Promise { - const applications = await sql` - SELECT id, posting_id AS "postingId", user_id AS "userId", candidate_statement AS "candidateStatement", created_at AS "createdAt" - FROM applications - WHERE posting_id = ${postingId}; + const data = await sql` + SELECT + a.id, + a.candidate_statement AS "candidateStatement", + a.created_at AS "createdAt", + u.id AS "userId", + u.username, + u.email, + u.phone, + u.full_name AS "fullName" + FROM applications a + JOIN users u ON a.user_id = u.id + WHERE a.posting_id = ${postingId}; `; - applications.forEach((application) => { + data.forEach((application) => { application.createdAt = new Date(application.createdAt); + application.user = { + id: application.userId, + username: application.username, + email: application.email, + phone: application.phone, + fullName: application.fullName + }; + delete application.userId; + delete application.username; + delete application.email; + delete application.phone; + delete application.fullName; }); - return applications; + return (data); } diff --git a/src/lib/index.server.ts b/src/lib/index.server.ts index 79d748b..c6db7d2 100644 --- a/src/lib/index.server.ts +++ b/src/lib/index.server.ts @@ -3,7 +3,7 @@ import path from 'path'; import fetch from 'node-fetch'; import { type Cookies, error } from '@sveltejs/kit'; import jwt from 'jsonwebtoken'; -import type { User } from '$lib/types'; +import type { Company, User } from '$lib/types'; // TODO: Handle saving custom avatar uploads export async function saveAvatar(user: User): Promise { @@ -14,6 +14,14 @@ export async function saveAvatar(user: User): Promise { fs.writeFileSync(filePath, avatar); } +export async function saveLogo(company: Company): Promise { + const url = `https://ui-avatars.com/api/?background=random&format=svg&name=${encodeURIComponent(company.name!)}`; + const response = await fetch(url, { headers: { accept: 'image/svg+xml' } }); + const avatar = await response.text(); + const filePath = path.join('static', 'uploads', 'logos', `${company.id}.svg`); + fs.writeFileSync(filePath, avatar); +} + // TODO: change to return null instead of -1 export function getUserPerms(cookies: Cookies): number { if (process.env.JWT_SECRET === undefined) { diff --git a/src/lib/types.ts b/src/lib/types.ts index ac51ac0..76435d9 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -65,4 +65,5 @@ export interface Application { postingTitle: string | null; candidateStatement: string; createdAt: Date; + user: User | null; } diff --git a/src/routes/api/posting/+server.ts b/src/routes/api/posting/+server.ts index 0ccac58..1ed4d81 100644 --- a/src/routes/api/posting/+server.ts +++ b/src/routes/api/posting/+server.ts @@ -1,8 +1,8 @@ -import { getPosting, getPostingFullData } from '$lib/db/index.server'; +import { getPosting, getPostingWithCompanyUser } from '$lib/db/index.server'; import { error, json } from '@sveltejs/kit'; export async function GET({ url }) { const id = url.searchParams.get('id'); if (!id) return new Response(error(400, 'No id provided')); - return json(await getPostingFullData(parseInt(id))); + return json(await getPostingWithCompanyUser(parseInt(id))); } diff --git a/src/routes/postings/+page.svelte b/src/routes/postings/+page.svelte index d5144f3..ea494b8 100644 --- a/src/routes/postings/+page.svelte +++ b/src/routes/postings/+page.svelte @@ -12,9 +12,9 @@ day: 'numeric' }; - function logoFallback(e: Event, posting: Posting) { + function logoFallback(e: Event, posting: Posting | undefined) { (e.target as HTMLImageElement).src = - `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')}`; } async function fetchDetails(id: number) { diff --git a/src/routes/postings/[posting]/+page.server.ts b/src/routes/postings/[posting]/+page.server.ts index 0fcba73..dece338 100644 --- a/src/routes/postings/[posting]/+page.server.ts +++ b/src/routes/postings/[posting]/+page.server.ts @@ -1,8 +1,8 @@ import type { PageServerLoad } from './$types'; -import { getPostingFullData, getPostings } from '$lib/db/index.server'; +import { getPostingWithCompanyUser, getPostings } from '$lib/db/index.server'; export const load: PageServerLoad = async ({ params }) => { return { - posting: await getPostingFullData(parseInt(params.posting)) + posting: await getPostingWithCompanyUser(parseInt(params.posting)) }; }; diff --git a/src/routes/postings/[posting]/apply/+page.server.ts b/src/routes/postings/[posting]/apply/+page.server.ts index e57e57b..ce024ff 100644 --- a/src/routes/postings/[posting]/apply/+page.server.ts +++ b/src/routes/postings/[posting]/apply/+page.server.ts @@ -1,16 +1,20 @@ import { type Actions, error, fail, redirect } from '@sveltejs/kit'; import type { PageServerLoad } from './$types'; -import { createApplication, getPostingFullData, getUserWithCompany } from '$lib/db/index.server'; -import { getUserId, getUserPerms } from '$lib/index.server'; +import { + createApplication, + getPostingWithCompanyUser, + getUserWithCompany +} from '$lib/db/index.server'; +import { getUserCompanyId, getUserId, getUserPerms } from '$lib/index.server'; import { PERMISSIONS } from '$lib/consts'; import type { Application } from '$lib/types'; export const load: PageServerLoad = async ({ params, cookies }) => { const id = parseInt(params.posting); const perms = getUserPerms(cookies); - if (perms >= 0 && (perms & PERMISSIONS.MANAGE_USERS) > 0) { + if (perms >= 0 && (perms & PERMISSIONS.APPLY_FOR_JOBS) > 0) { return { - posting: await getPostingFullData(id) + posting: await getPostingWithCompanyUser(id) }; } error(403, 'Unauthorized'); diff --git a/src/routes/postings/[posting]/apply/+page.svelte b/src/routes/postings/[posting]/apply/+page.svelte index f402912..c5f6b03 100644 --- a/src/routes/postings/[posting]/apply/+page.svelte +++ b/src/routes/postings/[posting]/apply/+page.svelte @@ -1,9 +1,8 @@ + +
+
+
+
+ Application Management (Total: {data.applications?.length || 0}) +
+
+
+ {#each data.applications as application} + + + {/each} +
+
+