import cleanup
This commit is contained in:
parent
1270fb3ae9
commit
77655c779d
@ -83,8 +83,7 @@ h1 {
|
||||
|
||||
.icon-16 {
|
||||
font-size: 16px !important;
|
||||
font-variation-settings:
|
||||
'FILL' 0,
|
||||
font-variation-settings: 'FILL' 0,
|
||||
'wght' 400,
|
||||
'GRAD' 0,
|
||||
'opsz' 20
|
||||
@ -92,8 +91,7 @@ h1 {
|
||||
|
||||
.icon-20 {
|
||||
font-size: 20px !important;
|
||||
font-variation-settings:
|
||||
'FILL' 0,
|
||||
font-variation-settings: 'FILL' 0,
|
||||
'wght' 400,
|
||||
'GRAD' 0,
|
||||
'opsz' 20
|
||||
@ -101,8 +99,7 @@ h1 {
|
||||
|
||||
.icon-48 {
|
||||
font-size: 48px !important;
|
||||
font-variation-settings:
|
||||
'FILL' 0,
|
||||
font-variation-settings: 'FILL' 0,
|
||||
'wght' 400,
|
||||
'GRAD' 0,
|
||||
'opsz' 20
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
<!doctype html>
|
||||
<!--suppress HtmlUnknownTarget -->
|
||||
<html lang="en" data-theme="">
|
||||
<html data-theme="" lang="en">
|
||||
<head>
|
||||
<title>FBLA 25</title>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link href="%sveltekit.assets%/favicon.png" rel="icon" />
|
||||
<meta content="width=device-width, initial-scale=1" name="viewport" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body data-sveltekit-preload-data="hover">
|
||||
|
||||
@ -18,9 +18,10 @@ export async function createUser(user: User): Promise<number> {
|
||||
const password_hash: string = await bcrypt.hash(user.password!, 12);
|
||||
|
||||
const response = await sql`
|
||||
INSERT INTO users (username, password_hash, perms, created_at, last_signin, active, email, phone, full_name, company_code)
|
||||
VALUES (${user.username}, ${password_hash}, ${user.perms}, NOW(), NOW(), ${user.active}, ${user.email}, ${user.phone}, ${user.fullName}, ${user.companyCode})
|
||||
RETURNING id;
|
||||
INSERT INTO users (username, password_hash, perms, created_at, last_signin, active, email, phone, full_name,
|
||||
company_code)
|
||||
VALUES (${user.username}, ${password_hash}, ${user.perms}, NOW(), NOW(), ${user.active}, ${user.email},
|
||||
${user.phone}, ${user.fullName}, ${user.companyCode}) RETURNING id;
|
||||
`;
|
||||
|
||||
// TODO: handle custom image uploads
|
||||
@ -40,15 +41,28 @@ export async function updateUser(user: User): Promise<number> {
|
||||
|
||||
// Construct the SQL query
|
||||
const response = await sql`UPDATE users
|
||||
SET
|
||||
username = ${user.username},
|
||||
${user.perms !== undefined ? sql`perms = ${user.perms},` : sql``}
|
||||
${user.active !== undefined ? sql`active = ${user.active},` : sql``}
|
||||
${password_hash !== null ? sql`password_hash = ${password_hash},` : sql``}
|
||||
email = ${user.email},
|
||||
phone = ${user.phone},
|
||||
full_name = ${user.fullName},
|
||||
company_code = ${user.companyCode}
|
||||
SET username = ${user.username},
|
||||
${
|
||||
user.perms !== undefined
|
||||
? sql`perms
|
||||
=
|
||||
${user.perms},`
|
||||
: sql``
|
||||
}
|
||||
${
|
||||
user.active !== undefined
|
||||
? sql`active
|
||||
=
|
||||
${user.active},`
|
||||
: sql``
|
||||
} ${
|
||||
password_hash !== null
|
||||
? sql`password_hash
|
||||
=
|
||||
${password_hash},`
|
||||
: sql``
|
||||
}
|
||||
email = ${user.email}, phone = ${user.phone}, full_name = ${user.fullName}, company_code = ${user.companyCode}
|
||||
WHERE id = ${user.id}
|
||||
RETURNING id;`;
|
||||
|
||||
@ -115,10 +129,17 @@ export async function getCompanies(searchQuery: string | null = null): Promise<C
|
||||
// should require MANAGE_USERS permission
|
||||
export async function getUser(id: number): Promise<User> {
|
||||
const [user] = await sql`
|
||||
SELECT id, username, perms,
|
||||
SELECT id,
|
||||
username,
|
||||
perms,
|
||||
created_at AT TIME ZONE 'UTC' AS "createdAt",
|
||||
last_signin AT TIME ZONE 'UTC' AS "lastSignIn",
|
||||
active, email, phone, full_name AS "fullName", company_id, company_code
|
||||
active,
|
||||
email,
|
||||
phone,
|
||||
full_name AS "fullName",
|
||||
company_id,
|
||||
company_code
|
||||
FROM users
|
||||
WHERE id = ${id};
|
||||
`;
|
||||
@ -134,8 +155,7 @@ export async function getUser(id: number): Promise<User> {
|
||||
|
||||
export async function getUserWithCompany(id: number): Promise<User> {
|
||||
const [user] = await sql`
|
||||
SELECT
|
||||
u.id,
|
||||
SELECT u.id,
|
||||
u.username,
|
||||
u.perms,
|
||||
u.email,
|
||||
@ -149,12 +169,10 @@ export async function getUserWithCompany(id: number): Promise<User> {
|
||||
c.description AS company_description,
|
||||
c.website AS company_website,
|
||||
c.created_at AS company_created_at
|
||||
FROM
|
||||
users u
|
||||
FROM users u
|
||||
LEFT JOIN
|
||||
companies c ON u.company_id = c.id
|
||||
WHERE
|
||||
u.id = ${id};
|
||||
WHERE u.id = ${id};
|
||||
`;
|
||||
if (!user) {
|
||||
error(404, 'User not found');
|
||||
@ -181,19 +199,14 @@ export async function getUserWithCompanyAndApplications(
|
||||
id: number
|
||||
): Promise<{ user: User; applications: Application[] }> {
|
||||
const data = await sql`
|
||||
WITH company_data AS (
|
||||
SELECT
|
||||
id,
|
||||
WITH company_data AS (SELECT id,
|
||||
name,
|
||||
description,
|
||||
website,
|
||||
created_at AT TIME ZONE 'UTC' AS "createdAt"
|
||||
FROM companies
|
||||
WHERE id = (SELECT company_id FROM users WHERE id = ${id})
|
||||
),
|
||||
user_data AS (
|
||||
SELECT
|
||||
id,
|
||||
WHERE id = (SELECT company_id FROM users WHERE id = ${id})),
|
||||
user_data AS (SELECT id,
|
||||
username,
|
||||
perms,
|
||||
email,
|
||||
@ -203,26 +216,17 @@ export async function getUserWithCompanyAndApplications(
|
||||
last_signin AT TIME ZONE 'UTC' AS "lastSignIn",
|
||||
active
|
||||
FROM users
|
||||
WHERE "id" = ${id}
|
||||
),
|
||||
application_data AS (
|
||||
SELECT
|
||||
id,
|
||||
WHERE "id" = ${id}),
|
||||
application_data AS (SELECT id,
|
||||
posting_id AS "postingId",
|
||||
(SELECT title FROM postings WHERE id = posting_id) AS "postingTitle",
|
||||
created_at AT TIME ZONE 'UTC' AS "createdAt"
|
||||
FROM applications
|
||||
WHERE "user_id" = ${id}
|
||||
)
|
||||
SELECT
|
||||
(
|
||||
SELECT row_to_json(company_data)
|
||||
FROM company_data
|
||||
) AS company,
|
||||
(
|
||||
SELECT row_to_json(user_data)
|
||||
FROM user_data
|
||||
) AS user,
|
||||
WHERE "user_id" = ${id})
|
||||
SELECT (SELECT row_to_json(company_data)
|
||||
FROM company_data) AS company,
|
||||
(SELECT row_to_json(user_data)
|
||||
FROM user_data) AS user,
|
||||
(
|
||||
SELECT json_agg(row_to_json(application_data))
|
||||
FROM application_data
|
||||
@ -258,7 +262,8 @@ export async function getUserWithCompanyAndApplications(
|
||||
// should require MANAGE_USERS permission
|
||||
export async function deleteUser(id: number): Promise<void> {
|
||||
await sql`
|
||||
DELETE FROM users
|
||||
DELETE
|
||||
FROM users
|
||||
WHERE id = ${id};
|
||||
`;
|
||||
}
|
||||
@ -283,8 +288,8 @@ export async function updateLastSignin(username: string): Promise<void> {
|
||||
export async function createCompany(company: Company): Promise<number> {
|
||||
const response = await sql`
|
||||
INSERT INTO companies (name, description, website, created_at, company_code)
|
||||
VALUES (${company.name}, ${company.description}, ${company.website}, NOW(), generate_company_code(CAST(CURRVAL('companies_id_seq') AS INT)))
|
||||
RETURNING id;
|
||||
VALUES (${company.name}, ${company.description}, ${company.website}, NOW(),
|
||||
generate_company_code(CAST(CURRVAL('companies_id_seq') AS INT))) RETURNING id;
|
||||
`;
|
||||
|
||||
await saveLogo(company);
|
||||
@ -295,9 +300,10 @@ export async function createCompany(company: Company): Promise<number> {
|
||||
export async function editCompany(company: Company): Promise<number> {
|
||||
const response = await sql`
|
||||
UPDATE companies
|
||||
SET name = ${company.name}, description = ${company.description}, website = ${company.website}
|
||||
WHERE id = ${company.id}
|
||||
RETURNING id;
|
||||
SET name = ${company.name},
|
||||
description = ${company.description},
|
||||
website = ${company.website}
|
||||
WHERE id = ${company.id} RETURNING id;
|
||||
`;
|
||||
|
||||
await saveLogo(company);
|
||||
@ -307,7 +313,8 @@ export async function editCompany(company: Company): Promise<number> {
|
||||
|
||||
export async function deleteCompany(id: number): Promise<void> {
|
||||
await sql`
|
||||
DELETE FROM companies
|
||||
DELETE
|
||||
FROM companies
|
||||
WHERE id = ${id};
|
||||
`;
|
||||
|
||||
@ -332,29 +339,21 @@ export async function getCompanyFullData(
|
||||
id: number
|
||||
): Promise<{ company: Company; users: User[]; postings: Posting[] }> {
|
||||
const data = await sql`
|
||||
WITH company_data AS (
|
||||
SELECT
|
||||
id,
|
||||
WITH company_data AS (SELECT id,
|
||||
name,
|
||||
description,
|
||||
website,
|
||||
created_at AT TIME ZONE 'UTC' AS "createdAt"
|
||||
FROM companies
|
||||
WHERE id = ${id}
|
||||
),
|
||||
user_data AS (
|
||||
SELECT
|
||||
id,
|
||||
WHERE id = ${id}),
|
||||
user_data AS (SELECT id,
|
||||
username,
|
||||
email,
|
||||
phone,
|
||||
full_name AS "fullName"
|
||||
FROM users
|
||||
WHERE "company_id" = ${id}
|
||||
),
|
||||
posting_data AS (
|
||||
SELECT
|
||||
id,
|
||||
WHERE "company_id" = ${id}),
|
||||
posting_data AS (SELECT id,
|
||||
title,
|
||||
description,
|
||||
employer_id AS "employerId",
|
||||
@ -367,21 +366,13 @@ export async function getCompanyFullData(
|
||||
updated_at AT TIME ZONE 'UTC' AS "updatedAt",
|
||||
flyer_link AS "flyerLink"
|
||||
FROM postings
|
||||
WHERE "company_id" = ${id}
|
||||
)
|
||||
SELECT
|
||||
(
|
||||
SELECT row_to_json(company_data)
|
||||
FROM company_data
|
||||
) AS company,
|
||||
(
|
||||
SELECT json_agg(row_to_json(user_data))
|
||||
FROM user_data
|
||||
) AS users,
|
||||
(
|
||||
SELECT json_agg(row_to_json(posting_data))
|
||||
FROM posting_data
|
||||
) AS postings;
|
||||
WHERE "company_id" = ${id})
|
||||
SELECT (SELECT row_to_json(company_data)
|
||||
FROM company_data) AS company,
|
||||
(SELECT json_agg(row_to_json(user_data))
|
||||
FROM user_data) AS users,
|
||||
(SELECT json_agg(row_to_json(posting_data))
|
||||
FROM posting_data) AS postings;
|
||||
`;
|
||||
|
||||
if (!data) {
|
||||
@ -432,9 +423,11 @@ export async function createPosting(posting: Posting): Promise<number> {
|
||||
}
|
||||
}
|
||||
const response = await sql`
|
||||
INSERT INTO postings (title, description, employer_id, address, employment_type, wage, link, tag_ids, created_at, updated_at, flyer_link, company_id)
|
||||
VALUES (${posting.title}, ${posting.description}, ${posting.employerId}, ${posting.address}, ${posting.employmentType}, ${posting.wage}, ${posting.link}, ${posting.tagIds}, NOW(), NOW(), ${posting.flyerLink}, ${posting.companyId})
|
||||
RETURNING id;
|
||||
INSERT INTO postings (title, description, employer_id, address, employment_type, wage, link, tag_ids, created_at,
|
||||
updated_at, flyer_link, company_id)
|
||||
VALUES (${posting.title}, ${posting.description}, ${posting.employerId}, ${posting.address},
|
||||
${posting.employmentType}, ${posting.wage}, ${posting.link}, ${posting.tagIds}, NOW(), NOW(),
|
||||
${posting.flyerLink}, ${posting.companyId}) RETURNING id;
|
||||
`;
|
||||
|
||||
return response[0].id;
|
||||
@ -457,9 +450,18 @@ export async function editPosting(posting: Posting): Promise<number> {
|
||||
|
||||
const response = await sql`
|
||||
UPDATE postings
|
||||
SET title = ${posting.title}, description = ${posting.description}, employer_id = ${posting.employerId}, address = ${posting.address}, employment_type = ${posting.employmentType}, wage = ${posting.wage}, link = ${posting.link}, tag_ids = ${posting.tagIds}, updated_at = NOW(), flyer_link = ${posting.flyerLink}, company_id = ${posting.companyId}
|
||||
WHERE id = ${posting.id}
|
||||
RETURNING id;
|
||||
SET title = ${posting.title},
|
||||
description = ${posting.description},
|
||||
employer_id = ${posting.employerId},
|
||||
address = ${posting.address},
|
||||
employment_type = ${posting.employmentType},
|
||||
wage = ${posting.wage},
|
||||
link = ${posting.link},
|
||||
tag_ids = ${posting.tagIds},
|
||||
updated_at = NOW(),
|
||||
flyer_link = ${posting.flyerLink},
|
||||
company_id = ${posting.companyId}
|
||||
WHERE id = ${posting.id} RETURNING id;
|
||||
`;
|
||||
|
||||
return response[0].id;
|
||||
@ -467,7 +469,8 @@ export async function editPosting(posting: Posting): Promise<number> {
|
||||
|
||||
export async function deletePosting(id: number): Promise<void> {
|
||||
await sql`
|
||||
DELETE FROM postings
|
||||
DELETE
|
||||
FROM postings
|
||||
WHERE id = ${id};
|
||||
`;
|
||||
}
|
||||
@ -476,17 +479,14 @@ export async function getCompanyEmployers(
|
||||
id: number
|
||||
): Promise<{ company: Company; users: User[] }> {
|
||||
const data = await sql`
|
||||
WITH company_data AS (
|
||||
SELECT
|
||||
id,
|
||||
WITH company_data AS (SELECT id,
|
||||
name,
|
||||
description,
|
||||
website,
|
||||
created_at AT TIME ZONE 'UTC' AS "createdAt",
|
||||
company_code AS "companyCode"
|
||||
FROM companies
|
||||
WHERE id = ${id}
|
||||
),
|
||||
WHERE id = ${id}),
|
||||
user_data AS (SELECT id,
|
||||
username,
|
||||
email,
|
||||
@ -497,15 +497,10 @@ export async function getCompanyEmployers(
|
||||
company_id as "companyId"
|
||||
FROM users
|
||||
WHERE "company_id" = ${id})
|
||||
SELECT
|
||||
(
|
||||
SELECT row_to_json(company_data)
|
||||
FROM company_data
|
||||
) AS company,
|
||||
(
|
||||
SELECT json_agg(row_to_json(user_data))
|
||||
FROM user_data
|
||||
) AS users;
|
||||
SELECT (SELECT row_to_json(company_data)
|
||||
FROM company_data) AS company,
|
||||
(SELECT json_agg(row_to_json(user_data))
|
||||
FROM user_data) AS users;
|
||||
`;
|
||||
|
||||
if (!data) {
|
||||
@ -539,17 +534,14 @@ export async function getCompanyEmployersAndRequests(
|
||||
id: number
|
||||
): Promise<{ company: Company; employers: User[]; requests: User[] }> {
|
||||
const data = await sql`
|
||||
WITH company_data AS (
|
||||
SELECT
|
||||
id,
|
||||
WITH company_data AS (SELECT id,
|
||||
name,
|
||||
description,
|
||||
website,
|
||||
created_at AT TIME ZONE 'UTC' AS "createdAt",
|
||||
company_code AS "companyCode"
|
||||
FROM companies
|
||||
WHERE id = ${id}
|
||||
),
|
||||
WHERE id = ${id}),
|
||||
employer_data AS (SELECT id,
|
||||
username,
|
||||
email,
|
||||
@ -570,19 +562,12 @@ export async function getCompanyEmployersAndRequests(
|
||||
company_id as "companyId"
|
||||
FROM users
|
||||
WHERE "company_code" = (SELECT company_code FROM companies WHERE id = ${id}))
|
||||
SELECT
|
||||
(
|
||||
SELECT row_to_json(company_data)
|
||||
FROM company_data
|
||||
) AS company,
|
||||
(
|
||||
SELECT json_agg(row_to_json(employer_data))
|
||||
FROM employer_data
|
||||
) AS employers,
|
||||
(
|
||||
SELECT json_agg(row_to_json(request_data))
|
||||
FROM request_data
|
||||
) AS requests;
|
||||
SELECT (SELECT row_to_json(company_data)
|
||||
FROM company_data) AS company,
|
||||
(SELECT json_agg(row_to_json(employer_data))
|
||||
FROM employer_data) AS employers,
|
||||
(SELECT json_agg(row_to_json(request_data))
|
||||
FROM request_data) AS requests;
|
||||
`;
|
||||
|
||||
if (!data) {
|
||||
@ -726,28 +711,20 @@ export async function getPosting(id: number): Promise<Posting> {
|
||||
|
||||
export async function getPostingWithCompanyUser(id: number): Promise<Posting> {
|
||||
const data = await sql`
|
||||
WITH company_data AS (
|
||||
SELECT
|
||||
id,
|
||||
WITH company_data AS (SELECT id,
|
||||
name,
|
||||
description,
|
||||
website,
|
||||
created_at AS "createdAt"
|
||||
FROM companies
|
||||
WHERE id = (SELECT company_id FROM postings WHERE id = ${id})
|
||||
),
|
||||
user_data AS (
|
||||
SELECT
|
||||
username,
|
||||
WHERE id = (SELECT company_id FROM postings WHERE id = ${id})),
|
||||
user_data AS (SELECT username,
|
||||
email,
|
||||
phone,
|
||||
full_name AS "fullName"
|
||||
FROM users
|
||||
WHERE "company_id" = (SELECT company_id FROM postings WHERE id = ${id})
|
||||
),
|
||||
posting_data AS (
|
||||
SELECT
|
||||
id,
|
||||
WHERE "company_id" = (SELECT company_id FROM postings WHERE id = ${id})),
|
||||
posting_data AS (SELECT id,
|
||||
title,
|
||||
description,
|
||||
employer_id AS "employerId",
|
||||
@ -760,17 +737,11 @@ export async function getPostingWithCompanyUser(id: number): Promise<Posting> {
|
||||
updated_at AT TIME ZONE 'UTC' AS "updatedAt",
|
||||
flyer_link AS "flyerLink"
|
||||
FROM postings
|
||||
WHERE id = ${id}
|
||||
)
|
||||
SELECT
|
||||
(
|
||||
SELECT row_to_json(company_data)
|
||||
FROM company_data
|
||||
) AS company,
|
||||
(
|
||||
SELECT row_to_json(user_data)
|
||||
FROM user_data
|
||||
) AS user,
|
||||
WHERE id = ${id})
|
||||
SELECT (SELECT row_to_json(company_data)
|
||||
FROM company_data) AS company,
|
||||
(SELECT row_to_json(user_data)
|
||||
FROM user_data) AS user,
|
||||
(
|
||||
SELECT row_to_json(posting_data)
|
||||
FROM posting_data
|
||||
@ -797,8 +768,7 @@ export async function getPostingWithCompanyUser(id: number): Promise<Posting> {
|
||||
export async function createApplication(application: Application): Promise<number> {
|
||||
const response = await sql`
|
||||
INSERT INTO applications (posting_id, user_id, candidate_statement, created_at)
|
||||
VALUES (${application.postingId}, ${application.userId}, ${application.candidateStatement}, NOW())
|
||||
RETURNING id;
|
||||
VALUES (${application.postingId}, ${application.userId}, ${application.candidateStatement}, NOW()) RETURNING id;
|
||||
`;
|
||||
|
||||
sendEmployerNotificationEmail(application.postingId).catch((err) => {
|
||||
@ -808,8 +778,9 @@ export async function createApplication(application: Application): Promise<numbe
|
||||
}
|
||||
|
||||
export async function deleteApplication(id: number): Promise<void> {
|
||||
const response = await sql`
|
||||
DELETE FROM applications
|
||||
await sql`
|
||||
DELETE
|
||||
FROM applications
|
||||
WHERE id = ${id};
|
||||
`;
|
||||
}
|
||||
@ -819,16 +790,17 @@ export async function deleteApplicationWithUser(
|
||||
userId: number
|
||||
): Promise<void> {
|
||||
console.log(applicationId, userId);
|
||||
const response = await sql`
|
||||
DELETE FROM applications
|
||||
WHERE id = ${applicationId} AND user_id = ${userId};
|
||||
await sql`
|
||||
DELETE
|
||||
FROM applications
|
||||
WHERE id = ${applicationId}
|
||||
AND user_id = ${userId};
|
||||
`;
|
||||
}
|
||||
|
||||
export async function getApplications(postingId: number): Promise<Application[]> {
|
||||
const data = await sql`
|
||||
SELECT
|
||||
a.id,
|
||||
SELECT a.id,
|
||||
a.candidate_statement AS "candidateStatement",
|
||||
a.created_at AS "createdAt",
|
||||
u.id AS "userId",
|
||||
@ -876,18 +848,13 @@ export async function getNotificationInfo(
|
||||
postingId: number
|
||||
): Promise<{ title: string; emails: string[] }> {
|
||||
const data = await sql`
|
||||
WITH posting_data AS (
|
||||
SELECT title, company_id
|
||||
WITH posting_data AS (SELECT title, company_id
|
||||
FROM postings
|
||||
WHERE id = ${postingId}
|
||||
),
|
||||
user_emails AS (
|
||||
SELECT email
|
||||
WHERE id = ${postingId}),
|
||||
user_emails AS (SELECT email
|
||||
FROM users
|
||||
WHERE company_id = (SELECT company_id FROM posting_data)
|
||||
)
|
||||
SELECT
|
||||
(SELECT title FROM posting_data) AS title,
|
||||
WHERE company_id = (SELECT company_id FROM posting_data))
|
||||
SELECT (SELECT title FROM posting_data) AS title,
|
||||
(SELECT json_agg(email) FROM user_emails) AS emails;
|
||||
`;
|
||||
|
||||
|
||||
@ -2,11 +2,11 @@
|
||||
import { page } from '$app/stores';
|
||||
</script>
|
||||
|
||||
<div style="padding-top: 32px" class="text-center">
|
||||
<div class="text-center" style="padding-top: 32px">
|
||||
<h1 class="text-9xl font-bold">
|
||||
{$page.status}
|
||||
</h1>
|
||||
<h1>Thats an error</h1>
|
||||
<h1>That's an error</h1>
|
||||
{#if $page.status === 404}
|
||||
<p>We cant seem to find the page you are looking for.</p>
|
||||
<p>The address may be mistyped, or the page may have moved or been deleted.</p>
|
||||
|
||||
@ -35,19 +35,19 @@
|
||||
</script>
|
||||
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..40,400,0,0&display=block&icon_names=account_circle,arrow_drop_down,arrow_drop_up,calendar_today,call,check,close,cloud_upload,dark_mode,delete,description,edit,group,info,light_mode,login,mail,open_in_new,person,search,sell,store,upload,visibility,visibility_off,work"
|
||||
rel="stylesheet"
|
||||
/>
|
||||
|
||||
<div class="flex min-h-screen flex-col">
|
||||
<div class="bottom-border bg-color sticky top-0 z-50 flex h-14 justify-between p-3 align-middle">
|
||||
<nav class="pt-1">
|
||||
<a href="/" class="hover-bg-color mr-1 rounded-md px-2 pb-2 pt-1.5">
|
||||
<a class="hover-bg-color mr-1 rounded-md px-2 pb-2 pt-1.5" href="/">
|
||||
<img
|
||||
class="inline-block"
|
||||
src="/mdevtriangle.svg"
|
||||
alt="MarinoDev Logo"
|
||||
class="inline-block"
|
||||
height="24"
|
||||
src="/mdevtriangle.svg"
|
||||
width="24"
|
||||
/>
|
||||
<div class="inline-block text-sm">Home</div>
|
||||
@ -76,7 +76,7 @@
|
||||
{/if}
|
||||
</nav>
|
||||
<div>
|
||||
<button onclick={toggleTheme} class="">
|
||||
<button class="" onclick={toggleTheme}>
|
||||
<span class="material-symbols-outlined hover-bg-color rounded-full p-1">
|
||||
{currentTheme === 'light' ? 'light_mode' : 'dark_mode'}
|
||||
</span>
|
||||
@ -103,13 +103,13 @@
|
||||
<div class="inline-block text-left align-top">
|
||||
<div class="inline-block pr-3">
|
||||
<p class="font-semibold">Drake Marino:</p>
|
||||
<a href="mailto:drake@marinodev.com" class="hyperlink-color hyperlink-underline"
|
||||
<a class="hyperlink-color hyperlink-underline" href="mailto:drake@marinodev.com"
|
||||
>drake@marinodev.com</a
|
||||
>
|
||||
</div>
|
||||
<div class="inline-block">
|
||||
<p class="font-semibold">Chetan Malkan:</p>
|
||||
<a href="mailto:chetan@marinodev.com" class="hyperlink-color hyperlink-underline"
|
||||
<a class="hyperlink-color hyperlink-underline" href="mailto:chetan@marinodev.com"
|
||||
>chetan@marinodev.com</a
|
||||
>
|
||||
</div>
|
||||
@ -121,8 +121,9 @@
|
||||
<div class="inline-block text-right align-top">
|
||||
<div class="font-semibold">Source Code:</div>
|
||||
<a
|
||||
class="hyperlink-color hyperlink-underline"
|
||||
href="https://git.marinodev.com/MarinoDev/FBLA25"
|
||||
class="hyperlink-color hyperlink-underline">https://git.marinodev.com/MarinoDev/FBLA25</a
|
||||
>https://git.marinodev.com/MarinoDev/FBLA25</a
|
||||
>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
|
||||
<div class="base-container">
|
||||
<div class="content pt-16">
|
||||
<img class="mx-auto" src="/mdevtriangle.svg" alt="MarinoDev Logo" height="256" width="256" />
|
||||
<img alt="MarinoDev Logo" class="mx-auto" height="256" src="/mdevtriangle.svg" width="256" />
|
||||
<h1 class="text-center text-8xl font-semibold">CareerConnect</h1>
|
||||
<h2 class="text-center text-3xl italic">Connecting Students with Opportunities</h2>
|
||||
<h2 class="pt-8 text-center">We are a platform that connects students with employers.</h2>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<h1>About</h1>
|
||||
<p>
|
||||
This is my submission for the 2025 FBLA Website Coding & Development event. It was built using
|
||||
<a href="https://svelte.dev/docs/kit/introduction" class="text-blue-600">SvelteKit</a>.
|
||||
<a class="text-blue-600" href="https://svelte.dev/docs/kit/introduction">SvelteKit</a>.
|
||||
</p>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { deleteApplicationWithUser, getUserWithCompanyAndApplications } from '$lib/db/index.server';
|
||||
import { getUserId } from '$lib/index.server';
|
||||
import { type Actions, fail, json, redirect } from '@sveltejs/kit';
|
||||
import { type Actions, fail } from '@sveltejs/kit';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { writeFileSync } from 'fs';
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
import type { PageProps } from './$types';
|
||||
|
||||
let applicationToDelete: number = $state(0);
|
||||
let { data, form }: PageProps = $props();
|
||||
let { data }: PageProps = $props();
|
||||
let resumeState = $state(data.resumeExists);
|
||||
|
||||
onMount(() => {
|
||||
@ -65,13 +65,10 @@
|
||||
});
|
||||
|
||||
function dropHandler(event: DragEvent) {
|
||||
// Prevent default behavior (Prevent file from being opened)
|
||||
event.preventDefault();
|
||||
|
||||
if (event.dataTransfer?.items) {
|
||||
const items = event.dataTransfer.items;
|
||||
// Use DataTransferItemList interface to access the file(s)
|
||||
// If dropped items aren't files, reject them
|
||||
if (items[0].kind === 'file') {
|
||||
const upload = items[0].getAsFile();
|
||||
if (upload?.type !== 'application/pdf') {
|
||||
@ -88,7 +85,7 @@
|
||||
}
|
||||
|
||||
async function handleSubmit(event: SubmitEvent) {
|
||||
event.preventDefault(); // Prevent default form submission
|
||||
event.preventDefault();
|
||||
|
||||
if (!file) {
|
||||
alert('Please select a file first');
|
||||
@ -96,7 +93,7 @@
|
||||
}
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('resume', file); // Manually append the file
|
||||
formData.append('resume', file);
|
||||
|
||||
try {
|
||||
const response = await fetch('?/uploadResume', {
|
||||
@ -123,14 +120,14 @@
|
||||
<div class="elevated separator-borders m-2 inline-block h-min min-w-max rounded align-top">
|
||||
<div class="inline-block p-4">
|
||||
<img
|
||||
id="avatar"
|
||||
alt="User avatar"
|
||||
class="mb-2 inline-block rounded-lg"
|
||||
height="240"
|
||||
id="avatar"
|
||||
onerror={avatarFallback}
|
||||
src="/uploads/avatars/{data.user.id
|
||||
? data.user.id
|
||||
: 'default'}.svg?timestamp=${Date.now()}"
|
||||
onerror={avatarFallback}
|
||||
alt="User avatar"
|
||||
height="240"
|
||||
width="240"
|
||||
/>
|
||||
{#if data.user.fullName}
|
||||
@ -169,8 +166,8 @@
|
||||
>Edit account</a
|
||||
>
|
||||
<button class="danger-border-color m-2 rounded-md border px-2.5 py-1" onclick={signOut}
|
||||
>Sign out</button
|
||||
>
|
||||
>Sign out
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-3">
|
||||
@ -217,17 +214,17 @@
|
||||
{#if resumeState}
|
||||
<a class="pb-2" href="/uploads/resumes/{data.user.id}.pdf" target="_blank">
|
||||
<button class="dull-primary-bg-color rounded-md px-2.5 py-1"
|
||||
><span class="material-symbols-outlined align-middle">open_in_new</span> View résumé</button
|
||||
>
|
||||
><span class="material-symbols-outlined align-middle">open_in_new</span> View résumé
|
||||
</button>
|
||||
</a>
|
||||
<button class="mb-2 ml-1 rounded-md border px-2.5 py-1" onclick={openUpload}
|
||||
><span class="material-symbols-outlined align-middle">upload</span> Upload new version</button
|
||||
>
|
||||
><span class="material-symbols-outlined align-middle">upload</span> Upload new version
|
||||
</button>
|
||||
{:else}
|
||||
<div class="">No résumé submitted.</div>
|
||||
<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</button
|
||||
>
|
||||
><span class="material-symbols-outlined align-middle">upload</span> Upload
|
||||
</button>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="top-border pt-2 font-semibold">
|
||||
@ -258,8 +255,9 @@
|
||||
onclick={() => {
|
||||
applicationToDelete = application.id;
|
||||
openConfirm();
|
||||
}}>delete</button
|
||||
>
|
||||
}}
|
||||
>delete
|
||||
</button>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
@ -267,7 +265,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form id="deleteConfirmModal" method="POST" class="modal">
|
||||
<form class="modal" id="deleteConfirmModal" method="POST">
|
||||
<div class="modal-content">
|
||||
<div class="mb-2 inline-flex w-full justify-between">
|
||||
<h2 class="font-semibold">Are you sure?</h2>
|
||||
@ -278,18 +276,20 @@
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button
|
||||
class="danger-bg-color rounded px-2 py-1"
|
||||
formaction="?/deleteApplication&id={applicationToDelete}"
|
||||
type="submit"
|
||||
formaction="?/deleteApplication&id={applicationToDelete}">Delete application</button
|
||||
>
|
||||
>Delete application
|
||||
</button>
|
||||
<button
|
||||
class="separator-borders bg-color rounded px-2 py-1"
|
||||
onclick={closeConfirm}
|
||||
type="button"
|
||||
onclick={closeConfirm}>Cancel</button
|
||||
>
|
||||
>Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<form id="uploadModal" method="POST" class="modal" onsubmit={handleSubmit}>
|
||||
<form class="modal" id="uploadModal" method="POST" onsubmit={handleSubmit}>
|
||||
<div class="modal-content">
|
||||
<div class="mb-2 inline-flex w-full justify-between">
|
||||
<h2 class="font-semibold">Résumé Upload</h2>
|
||||
@ -297,22 +297,19 @@
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
role="region"
|
||||
class="dull-primary-border-color rounded-lg border-2 border-dashed"
|
||||
ondrop={dropHandler}
|
||||
ondragover={dragOverHandler}
|
||||
ondrop={dropHandler}
|
||||
role="region"
|
||||
>
|
||||
<label for="resume" class="cursor-pointer p-4">
|
||||
<label class="cursor-pointer p-4" for="resume">
|
||||
<div class="text-center">
|
||||
<span class="material-symbols-outlined icon-48">cloud_upload</span>
|
||||
<h3>Drag & drop your résumé here</h3>
|
||||
<p class="">
|
||||
or <span class="hyperlink-color hyperlink-underline">click here to browse.</span>
|
||||
</p>
|
||||
<!-- <label class="dull-primary-bg-color cursor-pointer rounded px-2 py-1" for="resume"-->
|
||||
<!-- >Select a file</label-->
|
||||
<!-- >-->
|
||||
<input bind:files type="file" id="resume" accept=".pdf" class="hidden" />
|
||||
<input accept=".pdf" bind:files class="hidden" id="resume" type="file" />
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
@ -322,9 +319,10 @@
|
||||
<button class="dull-primary-bg-color rounded px-2 py-1" type="submit">Submit</button>
|
||||
<button
|
||||
class="separator-borders bg-color rounded px-2 py-1"
|
||||
onclick={closeUpload}
|
||||
type="button"
|
||||
onclick={closeUpload}>Cancel</button
|
||||
>
|
||||
>Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { deleteUser, getUser, getUserWithCompany, updateUser } from '$lib/db/index.server';
|
||||
import { deleteUser, getUserWithCompany, updateUser } from '$lib/db/index.server';
|
||||
import { type Actions, fail, redirect } from '@sveltejs/kit';
|
||||
import { PERMISSIONS } from '$lib/consts';
|
||||
import { getUserId } from '$lib/index.server';
|
||||
import type { User } from '$lib/types';
|
||||
import path from 'path';
|
||||
|
||||
export const load: PageServerLoad = async ({ cookies }) => {
|
||||
const id = getUserId(cookies);
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
import { enhance } from '$app/forms';
|
||||
import type { PageProps } from './$types';
|
||||
import { telFormatter } from '$lib/shared.svelte';
|
||||
|
||||
let permsAccordions: boolean[] = [false, false, false];
|
||||
|
||||
onMount(() => {
|
||||
@ -91,63 +92,63 @@
|
||||
<div class="bottom-border flex place-content-between">
|
||||
<div class="p-3 font-semibold">Edit Account</div>
|
||||
</div>
|
||||
<form method="POST" class="px-4" autocomplete="off" use:enhance>
|
||||
<form autocomplete="off" class="px-4" method="POST" use:enhance>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Username <span class="danger-color">*</span>
|
||||
<input
|
||||
type="text"
|
||||
name="username"
|
||||
id="username"
|
||||
value={data.user?.username}
|
||||
placeholder="Username"
|
||||
class="w-full rounded font-normal"
|
||||
id="username"
|
||||
name="username"
|
||||
placeholder="Username"
|
||||
type="text"
|
||||
value={data.user?.username}
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Full name <span class="danger-color">*</span>
|
||||
<input
|
||||
type="text"
|
||||
name="fullName"
|
||||
id="fullName"
|
||||
value={data.user?.fullName}
|
||||
placeholder="Full name"
|
||||
class="w-full rounded font-normal"
|
||||
id="fullName"
|
||||
name="fullName"
|
||||
placeholder="Full name"
|
||||
required
|
||||
type="text"
|
||||
value={data.user?.fullName}
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Email <span class="danger-color">*</span>
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
id="email"
|
||||
value={data.user?.email}
|
||||
placeholder="Email"
|
||||
class="w-full rounded font-normal"
|
||||
id="email"
|
||||
name="email"
|
||||
placeholder="Email"
|
||||
required
|
||||
type="email"
|
||||
value={data.user?.email}
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Phone (optional)
|
||||
<input
|
||||
type="tel"
|
||||
name="phone"
|
||||
id="phone"
|
||||
value={data.user?.phone}
|
||||
placeholder="Phone"
|
||||
class="w-full rounded font-normal"
|
||||
id="phone"
|
||||
name="phone"
|
||||
pattern="([0-9]\{3}) [0-9]\{3}-[0-9]\{3}"
|
||||
placeholder="Phone"
|
||||
type="tel"
|
||||
value={data.user?.phone}
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Company code (optional)
|
||||
<input
|
||||
type="text"
|
||||
name="companyCode"
|
||||
id="companyCode"
|
||||
placeholder="Company code"
|
||||
value={data.user?.companyCode}
|
||||
class="w-full rounded font-normal"
|
||||
id="companyCode"
|
||||
name="companyCode"
|
||||
placeholder="Company code"
|
||||
type="text"
|
||||
value={data.user?.companyCode}
|
||||
/>
|
||||
</div>
|
||||
<p class="low-emphasis-text pb-4">
|
||||
@ -161,43 +162,46 @@
|
||||
<div class="flex justify-between">
|
||||
<button
|
||||
class="dull-primary-bg-color mb-4 mt-2 rounded px-2 py-1"
|
||||
formaction="?/submit"
|
||||
type="submit"
|
||||
formaction="?/submit">Update account</button
|
||||
>
|
||||
>Update account
|
||||
</button>
|
||||
<button
|
||||
class="danger-bg-color mb-4 mt-2 rounded px-2 py-1"
|
||||
onclick={openConfirm}
|
||||
type="button"
|
||||
onclick={openConfirm}>Delete account</button
|
||||
>
|
||||
>Delete account
|
||||
</button>
|
||||
</div>
|
||||
<div id="deleteConfirmModal" class="modal">
|
||||
<div class="modal" id="deleteConfirmModal">
|
||||
<div class="modal-content">
|
||||
<div class="mb-2 inline-flex w-full justify-between">
|
||||
<h2 class="font-semibold">Are you sure?</h2>
|
||||
<button class="material-symbols-outlined" onclick={closeConfirm} type="button"
|
||||
>close</button
|
||||
>
|
||||
>close
|
||||
</button>
|
||||
</div>
|
||||
<p>This will permanently delete your account. This action cannot be undone.</p>
|
||||
<p>Please type "I understand" into the box below to confirm</p>
|
||||
<input
|
||||
type="text"
|
||||
name="confirm"
|
||||
id="confirm"
|
||||
placeholder="I understand"
|
||||
class="w-full rounded font-normal"
|
||||
id="confirm"
|
||||
name="confirm"
|
||||
pattern="I understand"
|
||||
placeholder="I understand"
|
||||
required
|
||||
type="text"
|
||||
/>
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button class="danger-bg-color rounded px-2 py-1" type="submit" formaction="?/delete"
|
||||
>Delete account</button
|
||||
>
|
||||
<button class="danger-bg-color rounded px-2 py-1" formaction="?/delete" type="submit"
|
||||
>Delete account
|
||||
</button>
|
||||
<button
|
||||
class="separator-borders bg-color rounded px-2 py-1"
|
||||
onclick={closeConfirm}
|
||||
type="button"
|
||||
onclick={closeConfirm}>Cancel</button
|
||||
>
|
||||
>Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { getCompanies, getUsers } from '$lib/db/index.server';
|
||||
import { getCompanies } from '$lib/db/index.server';
|
||||
import { PERMISSIONS } from '$lib/consts';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import { getUserPerms } from '$lib/index.server';
|
||||
|
||||
@ -21,11 +21,11 @@
|
||||
<form action="" class="flex p-4">
|
||||
<div class="search-bar">
|
||||
<input
|
||||
type="search"
|
||||
name="searchCompanies"
|
||||
id="searchCompanies"
|
||||
placeholder="Search Companies"
|
||||
class="search-cancel"
|
||||
id="searchCompanies"
|
||||
name="searchCompanies"
|
||||
placeholder="Search Companies"
|
||||
type="search"
|
||||
/>
|
||||
<button><span class="material-symbols-outlined">search</span></button>
|
||||
</div>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { getPostings, getUsers } from '$lib/db/index.server';
|
||||
import { getPostings } from '$lib/db/index.server';
|
||||
import { PERMISSIONS } from '$lib/consts';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import { getUserPerms } from '$lib/index.server';
|
||||
|
||||
@ -23,11 +23,11 @@
|
||||
<form action="" class="flex p-4">
|
||||
<div class="search-bar">
|
||||
<input
|
||||
type="search"
|
||||
name="searchPostings"
|
||||
id="searchPostings"
|
||||
placeholder="Search Postings"
|
||||
class="search-cancel"
|
||||
id="searchPostings"
|
||||
name="searchPostings"
|
||||
placeholder="Search Postings"
|
||||
type="search"
|
||||
/>
|
||||
<button><span class="material-symbols-outlined">search</span></button>
|
||||
</div>
|
||||
|
||||
@ -21,11 +21,11 @@
|
||||
<form action="" class="flex p-4">
|
||||
<div class="search-bar">
|
||||
<input
|
||||
type="search"
|
||||
name="searchTags"
|
||||
id="searchTags"
|
||||
placeholder="Search Tags"
|
||||
class="search-cancel"
|
||||
id="searchTags"
|
||||
name="searchTags"
|
||||
placeholder="Search Tags"
|
||||
type="search"
|
||||
/>
|
||||
<button><span class="material-symbols-outlined">search</span></button>
|
||||
</div>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { userPerms, employerPerms, adminPerms } from '$lib/shared.svelte';
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
const dateFormatOptions: Intl.DateTimeFormatOptions = {
|
||||
@ -29,11 +30,11 @@
|
||||
<form action="" class="flex p-4">
|
||||
<div class="search-bar">
|
||||
<input
|
||||
type="search"
|
||||
name="searchUsers"
|
||||
id="searchUsers"
|
||||
placeholder="Search Users"
|
||||
class="search-cancel"
|
||||
id="searchUsers"
|
||||
name="searchUsers"
|
||||
placeholder="Search Users"
|
||||
type="search"
|
||||
/>
|
||||
<button><span class="material-symbols-outlined">search</span></button>
|
||||
</div>
|
||||
|
||||
@ -27,11 +27,11 @@
|
||||
<div class="elevated separator-borders m-2 inline-block h-min min-w-max rounded align-top">
|
||||
<div class="inline-block p-4">
|
||||
<img
|
||||
class="mb-2 inline-block rounded-lg"
|
||||
src="/uploads/avatars/{data.user.id}.svg?timestamp=${Date.now()}"
|
||||
alt="User avatar"
|
||||
onerror={avatarFallback}
|
||||
class="mb-2 inline-block rounded-lg"
|
||||
height="240"
|
||||
onerror={avatarFallback}
|
||||
src="/uploads/avatars/{data.user.id}.svg?timestamp=${Date.now()}"
|
||||
width="240"
|
||||
/>
|
||||
{#if data.user.fullName}
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
import type { PageProps } from './$types';
|
||||
import { PERMISSIONS } from '$lib/consts';
|
||||
import { userPerms, employerPerms, adminPerms, telFormatter } from '$lib/shared.svelte';
|
||||
|
||||
let permsAccordions: boolean[] = [false, false, false];
|
||||
|
||||
let passwordVisible = $state(false);
|
||||
@ -104,32 +105,32 @@
|
||||
Edit User {data.user.username}{data.user.fullName ? ` (${data.user.fullName})` : ''}
|
||||
</div>
|
||||
</div>
|
||||
<form method="POST" class="px-4" autocomplete="off" use:enhance>
|
||||
<form autocomplete="off" class="px-4" method="POST" use:enhance>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Username <span class="text-red-500">*</span>
|
||||
<input
|
||||
type="text"
|
||||
name="username"
|
||||
id="username"
|
||||
value={data.user?.username}
|
||||
placeholder="Username"
|
||||
class="w-full rounded font-normal"
|
||||
id="username"
|
||||
name="username"
|
||||
placeholder="Username"
|
||||
required
|
||||
type="text"
|
||||
value={data.user?.username}
|
||||
/>
|
||||
</div>
|
||||
<div class="relative pt-4 text-sm font-semibold">
|
||||
New password (optional)
|
||||
<input
|
||||
type="password"
|
||||
name="password"
|
||||
id="password"
|
||||
placeholder="New password"
|
||||
class="w-full rounded font-normal"
|
||||
id="password"
|
||||
name="password"
|
||||
placeholder="New password"
|
||||
type="password"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onclick={showPassword}
|
||||
class="absolute right-2.5 -translate-y-1/2 transform pt-12"
|
||||
onclick={showPassword}
|
||||
type="button"
|
||||
>
|
||||
<span class="material-symbols-outlined"
|
||||
>{passwordVisible ? 'visibility' : 'visibility_off'}</span
|
||||
@ -139,48 +140,48 @@
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Full name <span class="danger-color">*</span>
|
||||
<input
|
||||
type="text"
|
||||
name="fullName"
|
||||
id="fullName"
|
||||
value={data.user?.fullName}
|
||||
placeholder="Full name"
|
||||
class="w-full rounded font-normal"
|
||||
id="fullName"
|
||||
name="fullName"
|
||||
placeholder="Full name"
|
||||
required
|
||||
type="text"
|
||||
value={data.user?.fullName}
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Email <span class="danger-color">*</span>
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
id="email"
|
||||
value={data.user?.email}
|
||||
placeholder="Email"
|
||||
class="w-full rounded font-normal"
|
||||
id="email"
|
||||
name="email"
|
||||
placeholder="Email"
|
||||
required
|
||||
type="email"
|
||||
value={data.user?.email}
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Phone (optional)
|
||||
<input
|
||||
type="tel"
|
||||
name="phone"
|
||||
id="phone"
|
||||
value={data.user?.phone}
|
||||
placeholder="Phone"
|
||||
class="w-full rounded font-normal"
|
||||
id="phone"
|
||||
name="phone"
|
||||
pattern="([0-9]\{3}) [0-9]\{3}-[0-9]\{3}"
|
||||
placeholder="Phone"
|
||||
type="tel"
|
||||
value={data.user?.phone}
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Company code (optional)
|
||||
<input
|
||||
type="text"
|
||||
name="companyCode"
|
||||
id="companyCode"
|
||||
placeholder="Company code"
|
||||
value={data.user?.companyCode}
|
||||
class="w-full rounded font-normal"
|
||||
id="companyCode"
|
||||
name="companyCode"
|
||||
placeholder="Company code"
|
||||
type="text"
|
||||
value={data.user?.companyCode}
|
||||
/>
|
||||
</div>
|
||||
<p class="low-emphasis-text">
|
||||
@ -195,12 +196,12 @@
|
||||
<span class="flex place-items-center">
|
||||
<span class="ml-1 mr-3"
|
||||
><input
|
||||
type="checkbox"
|
||||
name="userPerms"
|
||||
id="userPerms"
|
||||
class="select-all"
|
||||
checked={(perms & userPerms) === userPerms}
|
||||
class="select-all"
|
||||
id="userPerms"
|
||||
indeterminate={(perms & userPerms) !== userPerms && (perms & userPerms) > 0}
|
||||
name="userPerms"
|
||||
type="checkbox"
|
||||
/></span
|
||||
>User Permissions
|
||||
</span>
|
||||
@ -211,25 +212,25 @@
|
||||
<div class="panel hidden p-2">
|
||||
<div>
|
||||
<div class="mb-1">
|
||||
<label for="view" class="flex place-items-center">
|
||||
<label class="flex place-items-center" for="view">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="view"
|
||||
id="view"
|
||||
class="permCheckbox mx-1"
|
||||
checked={(perms & PERMISSIONS.VIEW) > 0}
|
||||
class="permCheckbox mx-1"
|
||||
id="view"
|
||||
name="view"
|
||||
type="checkbox"
|
||||
/>
|
||||
<span class="ml-2">View access</span></label
|
||||
>
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<label for="apply" class="flex place-items-center">
|
||||
<label class="flex place-items-center" for="apply">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="apply"
|
||||
id="apply"
|
||||
class="permCheckbox mx-1"
|
||||
checked={(perms & PERMISSIONS.APPLY_FOR_JOBS) > 0}
|
||||
class="permCheckbox mx-1"
|
||||
id="apply"
|
||||
name="apply"
|
||||
type="checkbox"
|
||||
/>
|
||||
<span class="ml-2">Apply for jobs</span></label
|
||||
>
|
||||
@ -245,13 +246,13 @@
|
||||
<span class="flex place-items-center">
|
||||
<span class="ml-1 mr-3"
|
||||
><input
|
||||
type="checkbox"
|
||||
name="companyPerms"
|
||||
id="companyPerms"
|
||||
class="select-all"
|
||||
checked={(perms & employerPerms) === employerPerms}
|
||||
class="select-all"
|
||||
id="companyPerms"
|
||||
indeterminate={(perms & employerPerms) !== employerPerms &&
|
||||
(perms & employerPerms) > 0}
|
||||
name="companyPerms"
|
||||
type="checkbox"
|
||||
/></span
|
||||
>Company Permissions
|
||||
</span>
|
||||
@ -262,25 +263,25 @@
|
||||
<div class="panel hidden p-2">
|
||||
<div>
|
||||
<div class="mb-1">
|
||||
<label for="submitPostings" class="flex place-items-center">
|
||||
<label class="flex place-items-center" for="submitPostings">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="submitPostings"
|
||||
id="submitPostings"
|
||||
checked={(perms & PERMISSIONS.SUBMIT_POSTINGS) >= 0}
|
||||
class="permCheckbox mx-1"
|
||||
id="submitPostings"
|
||||
name="submitPostings"
|
||||
type="checkbox"
|
||||
/>
|
||||
<span class="ml-2">Submit postings</span></label
|
||||
>
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<label for="manageEmployers" class="flex place-items-center">
|
||||
<label class="flex place-items-center" for="manageEmployers">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="manageEmployers"
|
||||
id="manageEmployers"
|
||||
checked={(perms & PERMISSIONS.MANAGE_EMPLOYERS) > 0}
|
||||
class="permCheckbox mx-1"
|
||||
id="manageEmployers"
|
||||
name="manageEmployers"
|
||||
type="checkbox"
|
||||
/>
|
||||
<span class="ml-2">Manage employers (within their company)</span></label
|
||||
>
|
||||
@ -296,12 +297,12 @@
|
||||
<span class="flex place-items-center">
|
||||
<span class="ml-1 mr-3"
|
||||
><input
|
||||
type="checkbox"
|
||||
name="adminPerms"
|
||||
id="adminPerms"
|
||||
class="select-all"
|
||||
checked={(perms & adminPerms) === adminPerms}
|
||||
class="select-all"
|
||||
id="adminPerms"
|
||||
indeterminate={(perms & adminPerms) !== adminPerms && (perms & adminPerms) > 0}
|
||||
name="adminPerms"
|
||||
type="checkbox"
|
||||
/></span
|
||||
>Admin Permissions
|
||||
</span>
|
||||
@ -312,49 +313,49 @@
|
||||
<div class="panel hidden p-2">
|
||||
<div>
|
||||
<div class="mb-1">
|
||||
<label for="manageTags" class="flex place-items-center">
|
||||
<label class="flex place-items-center" for="manageTags">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="manageTags"
|
||||
id="manageTags"
|
||||
checked={(perms & PERMISSIONS.MANAGE_TAGS) > 0}
|
||||
class="permCheckbox mx-1"
|
||||
id="manageTags"
|
||||
name="manageTags"
|
||||
type="checkbox"
|
||||
/>
|
||||
<span class="ml-2">Manage tags</span></label
|
||||
>
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<label for="managePostings" class="flex place-items-center">
|
||||
<label class="flex place-items-center" for="managePostings">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="managePostings"
|
||||
id="managePostings"
|
||||
checked={(perms & PERMISSIONS.MANAGE_POSTINGS) > 0}
|
||||
class="permCheckbox mx-1"
|
||||
id="managePostings"
|
||||
name="managePostings"
|
||||
type="checkbox"
|
||||
/>
|
||||
<span class="ml-2">Manage postings</span></label
|
||||
>
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<label for="manageUsers" class="flex place-items-center">
|
||||
<label class="flex place-items-center" for="manageUsers">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="manageUsers"
|
||||
id="manageUsers"
|
||||
checked={(perms & PERMISSIONS.MANAGE_USERS) > 0}
|
||||
class="permCheckbox mx-1"
|
||||
id="manageUsers"
|
||||
name="manageUsers"
|
||||
type="checkbox"
|
||||
/>
|
||||
<span class="ml-2">Manage users</span></label
|
||||
>
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<label for="manageCompanies" class="flex place-items-center">
|
||||
<label class="flex place-items-center" for="manageCompanies">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="manageCompanies"
|
||||
id="manageCompanies"
|
||||
checked={(perms & PERMISSIONS.MANAGE_COMPANIES) > 0}
|
||||
class="permCheckbox mx-1"
|
||||
id="manageCompanies"
|
||||
name="manageCompanies"
|
||||
type="checkbox"
|
||||
/>
|
||||
<span class="ml-2">Manage companies</span></label
|
||||
>
|
||||
@ -362,13 +363,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<label for="accountActive" class="flex place-items-center p-2">
|
||||
<label class="flex place-items-center p-2" for="accountActive">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="accountActive"
|
||||
id="accountActive"
|
||||
checked={data.user?.active}
|
||||
class="permCheckbox mx-1"
|
||||
id="accountActive"
|
||||
name="accountActive"
|
||||
type="checkbox"
|
||||
/>
|
||||
<span class="ml-2">Account active</span></label
|
||||
>
|
||||
@ -379,23 +380,25 @@
|
||||
<div class="flex justify-between">
|
||||
<button
|
||||
class="dull-primary-bg-color mb-4 mt-2 rounded px-2 py-1"
|
||||
formaction="?/submit"
|
||||
type="submit"
|
||||
formaction="?/submit">Save user</button
|
||||
>
|
||||
>Save user
|
||||
</button>
|
||||
<button
|
||||
class="danger-bg-color mb-4 mt-2 rounded px-2 py-1"
|
||||
onclick={openConfirm}
|
||||
type="button"
|
||||
onclick={openConfirm}>Delete user</button
|
||||
>
|
||||
>Delete user
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<form id="deleteConfirmModal" class="modal" method="POST" use:enhance>
|
||||
<form class="modal" id="deleteConfirmModal" method="POST" use:enhance>
|
||||
<div class="modal-content">
|
||||
<div class="mb-2 inline-flex w-full justify-between">
|
||||
<h2 class="font-semibold">Are you sure?</h2>
|
||||
<button class="material-symbols-outlined" onclick={closeConfirm} type="button"
|
||||
>close</button
|
||||
>
|
||||
>close
|
||||
</button>
|
||||
</div>
|
||||
<p>
|
||||
This will permanently delete user <span class="font-semibold">{data.user?.username}.</span
|
||||
@ -403,23 +406,24 @@
|
||||
</p>
|
||||
<p>Please type "I understand" into the box below to confirm</p>
|
||||
<input
|
||||
type="text"
|
||||
name="confirm"
|
||||
id="confirm"
|
||||
placeholder="I understand"
|
||||
class="w-full rounded font-normal"
|
||||
id="confirm"
|
||||
name="confirm"
|
||||
pattern="I understand"
|
||||
placeholder="I understand"
|
||||
required
|
||||
type="text"
|
||||
/>
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button class="danger-bg-color rounded px-2 py-1" type="submit" formaction="?/delete"
|
||||
>Delete user</button
|
||||
>
|
||||
<button class="danger-bg-color rounded px-2 py-1" formaction="?/delete" type="submit"
|
||||
>Delete user
|
||||
</button>
|
||||
<button
|
||||
class="separator-borders bg-color rounded px-2 py-1"
|
||||
onclick={closeConfirm}
|
||||
type="button"
|
||||
onclick={closeConfirm}>Cancel</button
|
||||
>
|
||||
>Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import { type Actions, error, fail, redirect } from '@sveltejs/kit';
|
||||
import { createUser, getUsers } from '$lib/db/index.server';
|
||||
import { createUser } from '$lib/db/index.server';
|
||||
import { PERMISSIONS } from '$lib/consts';
|
||||
import { getUserPerms } from '$lib/index.server';
|
||||
import type { User } from '$lib/types';
|
||||
import { employerPerms, userPerms } from '$lib/shared.svelte';
|
||||
import type { PageServerLoad } from '../../../../../.svelte-kit/types/src/routes/admin/users/$types';
|
||||
|
||||
export const load: PageServerLoad = async ({ cookies, url }) => {
|
||||
export const load: PageServerLoad = async ({ cookies }) => {
|
||||
const perms = getUserPerms(cookies);
|
||||
if (!(perms >= 0 && (perms & PERMISSIONS.MANAGE_USERS) > 0)) {
|
||||
error(403, 'Unauthorized');
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
import { enhance } from '$app/forms';
|
||||
import type { PageProps } from './$types';
|
||||
import { telFormatter } from '$lib/shared.svelte';
|
||||
|
||||
let permsAccordions: boolean[] = [false, false, false];
|
||||
|
||||
let passwordVisible = $state(false);
|
||||
@ -85,32 +86,32 @@
|
||||
<div class="bottom-border flex place-content-between">
|
||||
<div class="p-3 font-semibold">Create new user</div>
|
||||
</div>
|
||||
<form method="POST" class="px-4" autocomplete="off" use:enhance>
|
||||
<form autocomplete="off" class="px-4" method="POST" use:enhance>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Username <span class="text-red-500">*</span>
|
||||
<input
|
||||
type="text"
|
||||
name="username"
|
||||
id="username"
|
||||
placeholder="Username"
|
||||
class="w-full rounded font-normal"
|
||||
id="username"
|
||||
name="username"
|
||||
placeholder="Username"
|
||||
required
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<div class="relative mt-4 text-sm font-semibold">
|
||||
Password <span class="text-red-500">*</span>
|
||||
<input
|
||||
type="password"
|
||||
name="password"
|
||||
id="password"
|
||||
placeholder="Password"
|
||||
class="w-full rounded font-normal"
|
||||
id="password"
|
||||
name="password"
|
||||
placeholder="Password"
|
||||
required
|
||||
type="password"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onclick={showPassword}
|
||||
class="absolute right-2.5 -translate-y-1/2 transform pt-12"
|
||||
onclick={showPassword}
|
||||
type="button"
|
||||
>
|
||||
<span class="material-symbols-outlined"
|
||||
>{passwordVisible ? 'visibility' : 'visibility_off'}</span
|
||||
@ -120,44 +121,44 @@
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Full name <span class="danger-color">*</span>
|
||||
<input
|
||||
type="text"
|
||||
name="fullName"
|
||||
id="fullName"
|
||||
placeholder="Full Name"
|
||||
class="w-full rounded font-normal"
|
||||
id="fullName"
|
||||
name="fullName"
|
||||
placeholder="Full Name"
|
||||
required
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Email <span class="danger-color">*</span>
|
||||
<input
|
||||
type="email"
|
||||
name="email"
|
||||
id="email"
|
||||
placeholder="Email"
|
||||
class="w-full rounded font-normal"
|
||||
id="email"
|
||||
name="email"
|
||||
placeholder="Email"
|
||||
required
|
||||
type="email"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Phone (optional)
|
||||
<input
|
||||
type="tel"
|
||||
name="phone"
|
||||
id="phone"
|
||||
placeholder="Phone"
|
||||
class="w-full rounded font-normal"
|
||||
id="phone"
|
||||
name="phone"
|
||||
pattern="([0-9]\{3}) [0-9]\{3}-[0-9]\{3}"
|
||||
placeholder="Phone"
|
||||
type="tel"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Company code (optional)
|
||||
<input
|
||||
type="text"
|
||||
name="companyCode"
|
||||
id="companyCode"
|
||||
placeholder="Company code"
|
||||
class="w-full rounded font-normal"
|
||||
id="companyCode"
|
||||
name="companyCode"
|
||||
placeholder="Company code"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<p class="low-emphasis-text">
|
||||
@ -172,11 +173,11 @@
|
||||
<span class="flex place-items-center">
|
||||
<span class="ml-1 mr-3"
|
||||
><input
|
||||
type="checkbox"
|
||||
name="userPerms"
|
||||
id="userPerms"
|
||||
class="select-all"
|
||||
id="userPerms"
|
||||
indeterminate={true}
|
||||
name="userPerms"
|
||||
type="checkbox"
|
||||
/></span
|
||||
>User Permissions
|
||||
</span>
|
||||
@ -187,20 +188,20 @@
|
||||
<div class="panel hidden p-2">
|
||||
<div>
|
||||
<div class="mb-1">
|
||||
<label for="view" class="flex place-items-center">
|
||||
<label class="flex place-items-center" for="view">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="view"
|
||||
id="view"
|
||||
checked={true}
|
||||
class="permCheckbox mx-1"
|
||||
id="view"
|
||||
name="view"
|
||||
type="checkbox"
|
||||
/>
|
||||
<span class="ml-2">View access</span></label
|
||||
>
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<label for="apply" class="flex place-items-center">
|
||||
<input type="checkbox" name="apply" id="apply" class="permCheckbox mx-1" />
|
||||
<label class="flex place-items-center" for="apply">
|
||||
<input class="permCheckbox mx-1" id="apply" name="apply" type="checkbox" />
|
||||
<span class="ml-2">Apply for jobs</span></label
|
||||
>
|
||||
</div>
|
||||
@ -215,10 +216,10 @@
|
||||
<span class="flex place-items-center">
|
||||
<span class="ml-1 mr-3"
|
||||
><input
|
||||
type="checkbox"
|
||||
name="companyPerms"
|
||||
id="companyPerms"
|
||||
class="select-all"
|
||||
id="companyPerms"
|
||||
name="companyPerms"
|
||||
type="checkbox"
|
||||
/></span
|
||||
>Company Permissions
|
||||
</span>
|
||||
@ -229,23 +230,23 @@
|
||||
<div class="panel hidden p-2">
|
||||
<div>
|
||||
<div class="mb-1">
|
||||
<label for="submitPostings" class="flex place-items-center">
|
||||
<label class="flex place-items-center" for="submitPostings">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="submitPostings"
|
||||
id="submitPostings"
|
||||
class="permCheckbox mx-1"
|
||||
id="submitPostings"
|
||||
name="submitPostings"
|
||||
type="checkbox"
|
||||
/>
|
||||
<span class="ml-2">Submit postings</span></label
|
||||
>
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<label for="manageEmployers" class="flex place-items-center">
|
||||
<label class="flex place-items-center" for="manageEmployers">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="manageEmployers"
|
||||
id="manageEmployers"
|
||||
class="permCheckbox mx-1"
|
||||
id="manageEmployers"
|
||||
name="manageEmployers"
|
||||
type="checkbox"
|
||||
/>
|
||||
<span class="ml-2">Manage employers (within their company)</span></label
|
||||
>
|
||||
@ -260,7 +261,7 @@
|
||||
>
|
||||
<span class="flex place-items-center">
|
||||
<span class="ml-1 mr-3"
|
||||
><input type="checkbox" name="adminPerms" id="adminPerms" class="select-all" /></span
|
||||
><input class="select-all" id="adminPerms" name="adminPerms" type="checkbox" /></span
|
||||
>Admin Permissions
|
||||
</span>
|
||||
<span class="material-symbols-outlined"
|
||||
@ -270,45 +271,45 @@
|
||||
<div class="panel hidden p-2">
|
||||
<div>
|
||||
<div class="mb-1">
|
||||
<label for="manageTags" class="flex place-items-center">
|
||||
<label class="flex place-items-center" for="manageTags">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="manageTags"
|
||||
id="manageTags"
|
||||
class="permCheckbox mx-1"
|
||||
id="manageTags"
|
||||
name="manageTags"
|
||||
type="checkbox"
|
||||
/>
|
||||
<span class="ml-2">Manage tags</span></label
|
||||
>
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<label for="managePostings" class="flex place-items-center">
|
||||
<label class="flex place-items-center" for="managePostings">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="managePostings"
|
||||
id="managePostings"
|
||||
class="permCheckbox mx-1"
|
||||
id="managePostings"
|
||||
name="managePostings"
|
||||
type="checkbox"
|
||||
/>
|
||||
<span class="ml-2">Manage postings</span></label
|
||||
>
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<label for="manageUsers" class="flex place-items-center">
|
||||
<label class="flex place-items-center" for="manageUsers">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="manageUsers"
|
||||
id="manageUsers"
|
||||
class="permCheckbox mx-1"
|
||||
id="manageUsers"
|
||||
name="manageUsers"
|
||||
type="checkbox"
|
||||
/>
|
||||
<span class="ml-2">Manage users</span></label
|
||||
>
|
||||
</div>
|
||||
<div class="mb-1">
|
||||
<label for="manageCompanies" class="flex place-items-center">
|
||||
<label class="flex place-items-center" for="manageCompanies">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="manageCompanies"
|
||||
id="manageCompanies"
|
||||
class="permCheckbox mx-1"
|
||||
id="manageCompanies"
|
||||
name="manageCompanies"
|
||||
type="checkbox"
|
||||
/>
|
||||
<span class="ml-2">Manage companies</span></label
|
||||
>
|
||||
@ -316,13 +317,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<label for="accountActive" class="flex place-items-center p-2">
|
||||
<label class="flex place-items-center p-2" for="accountActive">
|
||||
<input
|
||||
type="checkbox"
|
||||
name="accountActive"
|
||||
id="accountActive"
|
||||
class="permCheckbox mx-1"
|
||||
checked
|
||||
class="permCheckbox mx-1"
|
||||
id="accountActive"
|
||||
name="accountActive"
|
||||
type="checkbox"
|
||||
/>
|
||||
<span class="ml-2">Account active</span></label
|
||||
>
|
||||
@ -332,9 +333,10 @@
|
||||
{/if}
|
||||
<button
|
||||
class="dull-primary-bg-color mb-4 mt-2 rounded px-2 py-1"
|
||||
formaction="?/submit"
|
||||
type="submit"
|
||||
formaction="?/submit">Create user</button
|
||||
>
|
||||
>Create user
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { getPosting, getPostingWithCompanyUser } from '$lib/db/index.server';
|
||||
import { getPostingWithCompanyUser } from '$lib/db/index.server';
|
||||
import { error, json } from '@sveltejs/kit';
|
||||
|
||||
export async function GET({ url }) {
|
||||
|
||||
@ -23,11 +23,11 @@
|
||||
<div class="bottom-border mb-4 flex justify-between">
|
||||
<div class="flex">
|
||||
<img
|
||||
class="mb-2 inline-block h-32 rounded-lg"
|
||||
src="/uploads/logos/{data.company.id}.jpg?timestamp=${Date.now()}"
|
||||
alt="Company Logo"
|
||||
onerror={logoFallback}
|
||||
class="mb-2 inline-block h-32 rounded-lg"
|
||||
height="128"
|
||||
onerror={logoFallback}
|
||||
src="/uploads/logos/{data.company.id}.jpg?timestamp=${Date.now()}"
|
||||
width="128"
|
||||
/>
|
||||
<div class="inline-block h-min pl-4">
|
||||
|
||||
@ -7,17 +7,17 @@
|
||||
|
||||
<div class="bottom-border h-10 pt-2 text-center">
|
||||
<a
|
||||
href={page.url.pathname.endsWith('employers') ? '.' : ''}
|
||||
class="p-2 {page.url.pathname.endsWith('edit')
|
||||
? 'primary-underline font-bold'
|
||||
: 'low-emphasis-text low-emphasis-text-button'}"
|
||||
href={page.url.pathname.endsWith('employers') ? '.' : ''}
|
||||
><span class="material-symbols-outlined align-bottom">store</span> Details</a
|
||||
>
|
||||
<a
|
||||
href={page.url.pathname.endsWith('edit') ? 'edit/employers' : ''}
|
||||
class="p-2 {page.url.pathname.endsWith('employers')
|
||||
? 'primary-underline font-bold'
|
||||
: 'low-emphasis-text low-emphasis-text-button'}"
|
||||
href={page.url.pathname.endsWith('edit') ? 'edit/employers' : ''}
|
||||
><span class="material-symbols-outlined align-bottom">group</span> Employers</a
|
||||
>
|
||||
</div>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { type Actions, error, fail, redirect } from '@sveltejs/kit';
|
||||
import { deleteCompany, editCompany, getCompany } from '$lib/db/index.server';
|
||||
import { PERMISSIONS } from '$lib/consts';
|
||||
import { getUserCompanyId, getUserPerms } from '$lib/index.server';
|
||||
import { getUserPerms } from '$lib/index.server';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import type { Company } from '$lib/types';
|
||||
|
||||
|
||||
@ -22,11 +22,11 @@
|
||||
<div class="content">
|
||||
<div class="m-4">
|
||||
<img
|
||||
class="mb-2 inline-block rounded-lg"
|
||||
src="/uploads/logos/{data.company.id}.jpg?timestamp=${Date.now()}"
|
||||
alt="User avatar"
|
||||
onerror={logoFallback}
|
||||
class="mb-2 inline-block rounded-lg"
|
||||
height="80"
|
||||
onerror={logoFallback}
|
||||
src="/uploads/logos/{data.company.id}.jpg?timestamp=${Date.now()}"
|
||||
width="80"
|
||||
/>
|
||||
<div class="inline-block pl-4 align-top">
|
||||
@ -38,38 +38,38 @@
|
||||
<div class="bottom-border flex place-content-between">
|
||||
<div class="p-3 font-semibold">Edit Company {data.company.name}</div>
|
||||
</div>
|
||||
<form method="POST" class="px-4" autocomplete="off" use:enhance>
|
||||
<form autocomplete="off" class="px-4" method="POST" use:enhance>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Name <span class="text-red-500">*</span>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
id="name"
|
||||
placeholder="Name"
|
||||
value={data.company?.name}
|
||||
class="w-full rounded font-normal"
|
||||
id="name"
|
||||
name="name"
|
||||
placeholder="Name"
|
||||
required
|
||||
type="text"
|
||||
value={data.company?.name}
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Description <span class="text-red-500">*</span>
|
||||
<textarea
|
||||
name="description"
|
||||
class="w-full rounded font-normal"
|
||||
id="description"
|
||||
rows="4"
|
||||
name="description"
|
||||
placeholder="Description"
|
||||
class="w-full rounded font-normal">{data.company?.description}</textarea
|
||||
rows="4">{data.company?.description}</textarea
|
||||
>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Website <span class="text-red-500">*</span>
|
||||
<input
|
||||
type="text"
|
||||
name="website"
|
||||
id="website"
|
||||
placeholder="Website"
|
||||
value={data.company?.website}
|
||||
class="w-full rounded font-normal"
|
||||
id="website"
|
||||
name="website"
|
||||
placeholder="Website"
|
||||
type="text"
|
||||
value={data.company?.website}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -79,23 +79,25 @@
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button
|
||||
class="dull-primary-bg-color mb-4 mt-2 rounded px-2 py-1"
|
||||
formaction="?/submit"
|
||||
type="submit"
|
||||
formaction="?/submit">Save company</button
|
||||
>
|
||||
>Save company
|
||||
</button>
|
||||
<button
|
||||
class="danger-bg-color mb-4 mt-2 rounded px-2 py-1"
|
||||
onclick={openConfirm}
|
||||
type="button"
|
||||
onclick={openConfirm}>Delete company</button
|
||||
>
|
||||
>Delete company
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<form id="deleteConfirmModal" class="modal" method="POST" use:enhance>
|
||||
<form class="modal" id="deleteConfirmModal" method="POST" use:enhance>
|
||||
<div class="modal-content">
|
||||
<div class="mb-2 inline-flex w-full justify-between">
|
||||
<h2 class="font-semibold">Are you sure?</h2>
|
||||
<button class="material-symbols-outlined" onclick={closeConfirm} type="button"
|
||||
>close</button
|
||||
>
|
||||
>close
|
||||
</button>
|
||||
</div>
|
||||
<p>
|
||||
This will permanently delete company <span class="font-semibold"
|
||||
@ -104,23 +106,24 @@
|
||||
</p>
|
||||
<p>Please type "I understand" into the box below to confirm</p>
|
||||
<input
|
||||
type="text"
|
||||
name="confirm"
|
||||
id="confirm"
|
||||
placeholder="I understand"
|
||||
class="w-full rounded font-normal"
|
||||
id="confirm"
|
||||
name="confirm"
|
||||
pattern="I understand"
|
||||
placeholder="I understand"
|
||||
required
|
||||
type="text"
|
||||
/>
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button class="danger-bg-color rounded px-2 py-1" type="submit" formaction="?/delete"
|
||||
>Delete company</button
|
||||
>
|
||||
<button class="danger-bg-color rounded px-2 py-1" formaction="?/delete" type="submit"
|
||||
>Delete company
|
||||
</button>
|
||||
<button
|
||||
class="separator-borders bg-color rounded px-2 py-1"
|
||||
onclick={closeConfirm}
|
||||
type="button"
|
||||
onclick={closeConfirm}>Cancel</button
|
||||
>
|
||||
>Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -1,10 +1,6 @@
|
||||
import { type Actions, error, fail, redirect } from '@sveltejs/kit';
|
||||
import { type Actions, error, fail } from '@sveltejs/kit';
|
||||
import {
|
||||
addEmployerToCompany,
|
||||
deleteCompany,
|
||||
editCompany,
|
||||
getCompany,
|
||||
getCompanyEmployers,
|
||||
getCompanyEmployersAndRequests,
|
||||
removeEmployerFromCompany
|
||||
} from '$lib/db/index.server';
|
||||
|
||||
@ -20,11 +20,11 @@
|
||||
<div class="content">
|
||||
<div class="m-4">
|
||||
<img
|
||||
class="mb-2 inline-block rounded-lg"
|
||||
src="/uploads/logos/{data.company.id}.jpg?timestamp=${Date.now()}"
|
||||
alt="User avatar"
|
||||
onerror={logoFallback}
|
||||
class="mb-2 inline-block rounded-lg"
|
||||
height="80"
|
||||
onerror={logoFallback}
|
||||
src="/uploads/logos/{data.company.id}.jpg?timestamp=${Date.now()}"
|
||||
width="80"
|
||||
/>
|
||||
<div class="inline-block pl-4 align-top">
|
||||
@ -66,13 +66,14 @@
|
||||
>{user.lastSignIn?.toLocaleDateString('en-US', dateFormatOptions) ||
|
||||
'unknown'}</td
|
||||
>
|
||||
<td class="material-symbols-outlined hover-bg-color danger-color m-1 rounded"
|
||||
><button
|
||||
<td class="material-symbols-outlined hover-bg-color danger-color m-1 rounded">
|
||||
<button
|
||||
onclick={() => {
|
||||
idToRemove = user.id;
|
||||
}}>close</button
|
||||
></td
|
||||
>
|
||||
}}
|
||||
>close
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
{/if}
|
||||
{/each}
|
||||
@ -91,23 +92,26 @@
|
||||
class="material-symbols-outlined"
|
||||
onclick={() => {
|
||||
idToRemove = null;
|
||||
}}>close</button
|
||||
>
|
||||
}}
|
||||
>close
|
||||
</button>
|
||||
</div>
|
||||
<p>This will remove this employer from the company.</p>
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button
|
||||
class="danger-bg-color rounded px-2 py-1"
|
||||
type="submit"
|
||||
formaction="?/removeEmployer&userId={idToRemove}">Remove</button
|
||||
>
|
||||
formaction="?/removeEmployer&userId={idToRemove}"
|
||||
>Remove
|
||||
</button>
|
||||
<button
|
||||
class="separator-borders bg-color rounded px-2 py-1"
|
||||
type="button"
|
||||
onclick={() => {
|
||||
idToRemove = null;
|
||||
}}>Cancel</button
|
||||
>
|
||||
}}
|
||||
>Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@ -147,18 +151,20 @@
|
||||
>{user.lastSignIn?.toLocaleDateString('en-US', dateFormatOptions) ||
|
||||
'unknown'}</td
|
||||
>
|
||||
<td class="material-symbols-outlined"
|
||||
><form method="POST" class="flex">
|
||||
<td class="material-symbols-outlined">
|
||||
<form method="POST" class="flex">
|
||||
<button
|
||||
class="hover-bg-color m-1 rounded text-green-600"
|
||||
formaction="?/addEmployer&userId={user.id}">check</button
|
||||
>
|
||||
formaction="?/addEmployer&userId={user.id}"
|
||||
>check
|
||||
</button>
|
||||
<button
|
||||
class="hover-bg-color danger-color m-1 rounded"
|
||||
formaction="?/removeEmployer&userId={user.id}">close</button
|
||||
>
|
||||
</form></td
|
||||
>
|
||||
formaction="?/removeEmployer&userId={user.id}"
|
||||
>close
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{/if}
|
||||
{/each}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { type Actions, fail, redirect } from '@sveltejs/kit';
|
||||
import { createCompany } from '$lib/db/index.server';
|
||||
import { PERMISSIONS } from '$lib/consts';
|
||||
import { getUserCompanyId, getUserPerms } from '$lib/index.server';
|
||||
import { getUserPerms } from '$lib/index.server';
|
||||
import type { Company } from '$lib/types';
|
||||
|
||||
export const actions: Actions = {
|
||||
|
||||
@ -11,38 +11,38 @@
|
||||
<div class="bottom-border flex place-content-between">
|
||||
<div class="p-3 font-semibold">Create new company</div>
|
||||
</div>
|
||||
<form method="POST" class="px-4" autocomplete="off" use:enhance>
|
||||
<form autocomplete="off" class="px-4" method="POST" use:enhance>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Name <span class="text-red-500">*</span>
|
||||
<input
|
||||
type="text"
|
||||
name="name"
|
||||
id="name"
|
||||
placeholder="Name"
|
||||
class="w-full rounded font-normal"
|
||||
id="name"
|
||||
name="name"
|
||||
placeholder="Name"
|
||||
required
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Description <span class="text-red-500">*</span>
|
||||
<textarea
|
||||
name="description"
|
||||
id="description"
|
||||
rows="4"
|
||||
placeholder="Description"
|
||||
class="w-full rounded font-normal"
|
||||
id="description"
|
||||
name="description"
|
||||
placeholder="Description"
|
||||
required
|
||||
rows="4"
|
||||
></textarea>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Website <span class="text-red-500">*</span>
|
||||
<input
|
||||
type="text"
|
||||
name="website"
|
||||
id="website"
|
||||
placeholder="Website"
|
||||
class="w-full rounded font-normal"
|
||||
id="website"
|
||||
name="website"
|
||||
placeholder="Website"
|
||||
required
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -51,9 +51,10 @@
|
||||
{/if}
|
||||
<button
|
||||
class="dull-primary-bg-color mb-4 mt-6 rounded px-2 py-1"
|
||||
formaction="?/submit"
|
||||
type="submit"
|
||||
formaction="?/submit">Create company</button
|
||||
>
|
||||
>Create company
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
</p>
|
||||
<p>
|
||||
If you are your company admin, first create your account (without inputting a code). Reach out
|
||||
to a CareerConnect admin to elevate your account privaleges. Then, go to the company page, and
|
||||
to a CareerConnect admin to elevate your account privileges. Then, go to the company page, and
|
||||
use the button in the top right to create a new company. Once created, you will be able to see
|
||||
the company code, which you can then give to your employees.
|
||||
</p>
|
||||
|
||||
@ -4,19 +4,23 @@
|
||||
import { onMount } from 'svelte';
|
||||
import { employmentTypeDisplayName, userState } from '$lib/shared.svelte';
|
||||
import { PERMISSIONS } from '$lib/consts';
|
||||
|
||||
let details: Posting | undefined = $state<Posting>();
|
||||
|
||||
// Formating for all dates on the page
|
||||
const dateFormatOptions: Intl.DateTimeFormatOptions = {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
};
|
||||
|
||||
// If logo isn't found on the server, use a placeholder
|
||||
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')}`;
|
||||
}
|
||||
|
||||
// Fetch the detail pane content of a posting
|
||||
async function fetchDetails(id: number) {
|
||||
const response = await fetch(`/api/posting?id=${id}`);
|
||||
details = await response.json();
|
||||
@ -30,6 +34,7 @@
|
||||
|
||||
let { data }: PageProps = $props();
|
||||
|
||||
// Initial fetch of the first posting
|
||||
onMount(async () => {
|
||||
await fetchDetails(data.postings[0].id);
|
||||
});
|
||||
@ -48,22 +53,14 @@
|
||||
<form action="" class="flex p-4">
|
||||
<div class="search-bar">
|
||||
<input
|
||||
type="search"
|
||||
name="searchQuery"
|
||||
id="searchQuery"
|
||||
placeholder="Search Postings"
|
||||
class="search-cancel"
|
||||
id="searchQuery"
|
||||
name="searchQuery"
|
||||
placeholder="Search Postings"
|
||||
type="search"
|
||||
/>
|
||||
<button><span class="material-symbols-outlined">search</span></button>
|
||||
</div>
|
||||
<!-- <button class="hover-bg-color mx-2 rounded py-2 pl-3 pr-2 text-sm"-->
|
||||
<!-- >Filter<span class="material-symbols-outlined icon-20 align-middle">arrow_drop_down</span-->
|
||||
<!-- ></button-->
|
||||
<!-- >-->
|
||||
<!-- <button class="hover-bg-color rounded py-2 pl-3 pr-2 text-sm"-->
|
||||
<!-- >Sort<span class="material-symbols-outlined icon-20 align-middle">arrow_drop_down</span-->
|
||||
<!-- ></button-->
|
||||
<!-- >-->
|
||||
</form>
|
||||
<div class="flex">
|
||||
<div class="right-border inline-block w-1/3">
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { getPostingWithCompanyUser, getPostings } from '$lib/db/index.server';
|
||||
import { getPostingWithCompanyUser } from '$lib/db/index.server';
|
||||
|
||||
export const load: PageServerLoad = async ({ params }) => {
|
||||
return {
|
||||
|
||||
@ -24,16 +24,16 @@
|
||||
<div class="bottom-border elevated-bg flex justify-between pb-2">
|
||||
<div class="inline-block">
|
||||
<img
|
||||
class="inline-block rounded"
|
||||
src="/uploads/logos/{data.posting.company.id}.jpg"
|
||||
alt="Company Logo"
|
||||
class="inline-block rounded"
|
||||
height="64"
|
||||
width="64"
|
||||
onerror={(e) => logoFallback(e, data.posting)}
|
||||
src="/uploads/logos/{data.posting.company.id}.jpg"
|
||||
width="64"
|
||||
/>
|
||||
<div class="inline-block pl-2 align-top">
|
||||
<h1>{data.posting.title}</h1>
|
||||
<a href="/companies/{data.posting.company.id}" class="hover-hyperlink text-xl"
|
||||
<a class="hover-hyperlink text-xl" href="/companies/{data.posting.company.id}"
|
||||
>{data.posting.company.name}</a
|
||||
>
|
||||
</div>
|
||||
|
||||
@ -1,11 +1,7 @@
|
||||
import { type Actions, error, fail, redirect } from '@sveltejs/kit';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import {
|
||||
createApplication,
|
||||
getPostingWithCompanyUser,
|
||||
getUserWithCompany
|
||||
} from '$lib/db/index.server';
|
||||
import { getUserCompanyId, getUserId, getUserPerms } from '$lib/index.server';
|
||||
import { createApplication, getPostingWithCompanyUser } from '$lib/db/index.server';
|
||||
import { getUserId, getUserPerms } from '$lib/index.server';
|
||||
import { PERMISSIONS } from '$lib/consts';
|
||||
import type { Application } from '$lib/types';
|
||||
|
||||
|
||||
@ -24,12 +24,12 @@
|
||||
<div class="bottom-border elevated-bg flex justify-between pb-2">
|
||||
<div class="inline-block">
|
||||
<img
|
||||
class="inline-block rounded"
|
||||
src="/uploads/logos/{data.posting?.company.id}.jpg"
|
||||
alt="Company Logo"
|
||||
class="inline-block rounded"
|
||||
height="64"
|
||||
width="64"
|
||||
onerror={(e) => logoFallback(e, data.posting)}
|
||||
src="/uploads/logos/{data.posting?.company.id}.jpg"
|
||||
width="64"
|
||||
/>
|
||||
<div class="inline-block pl-2 align-top">
|
||||
<h1>{data.posting.title}</h1>
|
||||
@ -84,16 +84,16 @@
|
||||
<div class="bottom-border flex place-content-between">
|
||||
<div class="p-3 font-semibold">Apply</div>
|
||||
</div>
|
||||
<form method="POST" class="px-4" autocomplete="off" use:enhance>
|
||||
<form autocomplete="off" class="px-4" method="POST" use:enhance>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Why do you believe you are the best fit for this role? <span class="text-red-500">*</span>
|
||||
<textarea
|
||||
name="candidateStatement"
|
||||
id="candidateStatement"
|
||||
rows="4"
|
||||
placeholder="Answer here"
|
||||
class="w-full rounded font-normal"
|
||||
id="candidateStatement"
|
||||
name="candidateStatement"
|
||||
placeholder="Answer here"
|
||||
required
|
||||
rows="4"
|
||||
></textarea>
|
||||
</div>
|
||||
<p>
|
||||
@ -107,9 +107,10 @@
|
||||
{/if}
|
||||
<button
|
||||
class="dull-primary-bg-color mb-4 mt-6 rounded px-2 py-1"
|
||||
formaction="?/submit"
|
||||
type="submit"
|
||||
formaction="?/submit">Submit application</button
|
||||
>
|
||||
>Submit application
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -7,18 +7,17 @@
|
||||
|
||||
<div class="bottom-border h-10 pt-2 text-center">
|
||||
<a
|
||||
href="applications"
|
||||
class="p-2 {page.url.pathname.endsWith('applications')
|
||||
? 'primary-underline font-bold'
|
||||
: 'low-emphasis-text low-emphasis-text-button'}"
|
||||
href="applications"
|
||||
><span class="material-symbols-outlined align-bottom">description</span> Applications</a
|
||||
>
|
||||
<a
|
||||
href="edit"
|
||||
class="p-2 {page.url.pathname.endsWith('edit')
|
||||
? 'primary-underline font-bold'
|
||||
: 'low-emphasis-text low-emphasis-text-button'}"
|
||||
><span class="material-symbols-outlined align-bottom">work</span> Details</a
|
||||
href="edit"><span class="material-symbols-outlined align-bottom">work</span> Details</a
|
||||
>
|
||||
</div>
|
||||
|
||||
|
||||
@ -1,11 +1,7 @@
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { getUserCompanyId, getUserPerms } from '$lib/index.server';
|
||||
import { PERMISSIONS } from '$lib/consts';
|
||||
import {
|
||||
deleteApplication,
|
||||
getApplications,
|
||||
getPostingWithCompanyUser
|
||||
} from '$lib/db/index.server';
|
||||
import { deleteApplication, getApplications } from '$lib/db/index.server';
|
||||
import { type Actions, error } from '@sveltejs/kit';
|
||||
|
||||
export const load: PageServerLoad = async ({ params, cookies }) => {
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { enhance } from '$app/forms';
|
||||
import type { PageProps } from './$types';
|
||||
import { employmentTypeDisplayName } from '$lib/shared.svelte';
|
||||
import type { Application, Posting } from '$lib/types';
|
||||
import type { Application } from '$lib/types';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
const dateFormatOptions: Intl.DateTimeFormatOptions = {
|
||||
@ -20,7 +18,7 @@
|
||||
const acc = document.getElementsByClassName('accordion');
|
||||
|
||||
for (let i = 0; i < acc.length; i++) {
|
||||
acc[i].addEventListener('click', function (this: HTMLElement, event: Event) {
|
||||
acc[i].addEventListener('click', function (this: HTMLElement) {
|
||||
this.classList.toggle('active');
|
||||
this.children[1].innerHTML = this.classList.contains('active')
|
||||
? 'arrow_drop_up'
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { type Actions, error, fail, redirect } from '@sveltejs/kit';
|
||||
import { deletePosting, editPosting, getPosting, getPostings, getUser } from '$lib/db/index.server';
|
||||
import { deletePosting, editPosting, getPosting } from '$lib/db/index.server';
|
||||
import { PERMISSIONS } from '$lib/consts';
|
||||
import { getUserCompanyId, getUserId, getUserPerms } from '$lib/index.server';
|
||||
import type { Posting } from '$lib/types';
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
<div class="bottom-border flex place-content-between">
|
||||
<div class="p-3 font-semibold">Edit {data.posting.title}</div>
|
||||
</div>
|
||||
<form method="POST" class="px-4" autocomplete="off" use:enhance>
|
||||
<form autocomplete="off" class="px-4" method="POST" use:enhance>
|
||||
{#if !userState.companyId}
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Company ID <span class="text-red-500">*</span>
|
||||
@ -38,45 +38,45 @@
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Title <span class="text-red-500">*</span>
|
||||
<input
|
||||
type="text"
|
||||
name="title"
|
||||
id="title"
|
||||
placeholder="Title"
|
||||
value={data.posting.title}
|
||||
class="w-full rounded font-normal"
|
||||
id="title"
|
||||
name="title"
|
||||
placeholder="Title"
|
||||
required
|
||||
type="text"
|
||||
value={data.posting.title}
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Description <span class="text-red-500">*</span>
|
||||
<textarea
|
||||
name="description"
|
||||
id="description"
|
||||
rows="4"
|
||||
placeholder="Description"
|
||||
class="w-full rounded font-normal"
|
||||
required>{data.posting.description}</textarea
|
||||
id="description"
|
||||
name="description"
|
||||
placeholder="Description"
|
||||
required
|
||||
rows="4">{data.posting.description}</textarea
|
||||
>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Address <span class="text-red-500">*</span>
|
||||
<input
|
||||
type="text"
|
||||
name="address"
|
||||
id="address"
|
||||
placeholder="Address"
|
||||
value={data.posting.address}
|
||||
class="w-full rounded font-normal"
|
||||
id="address"
|
||||
name="address"
|
||||
placeholder="Address"
|
||||
required
|
||||
type="text"
|
||||
value={data.posting.address}
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
<label for="employmentType">Employment type <span class="text-red-500">*</span></label>
|
||||
<select
|
||||
name="employmentType"
|
||||
id="employmentType"
|
||||
value={data.posting.employmentType}
|
||||
class="w-full rounded font-normal"
|
||||
id="employmentType"
|
||||
name="employmentType"
|
||||
value={data.posting.employmentType}
|
||||
>
|
||||
<option value="full_time">Full time</option>
|
||||
<option value="part_time">Part time</option>
|
||||
@ -86,34 +86,34 @@
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Wage (optional)
|
||||
<input
|
||||
type="text"
|
||||
name="wage"
|
||||
id="wage"
|
||||
placeholder="Wage"
|
||||
value={data.posting.wage}
|
||||
class="w-full rounded font-normal"
|
||||
id="wage"
|
||||
name="wage"
|
||||
placeholder="Wage"
|
||||
type="text"
|
||||
value={data.posting.wage}
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Link to external posting information (optional)
|
||||
<input
|
||||
type="text"
|
||||
name="link"
|
||||
id="link"
|
||||
placeholder="Link"
|
||||
value={data.posting.link}
|
||||
class="w-full rounded font-normal"
|
||||
id="link"
|
||||
name="link"
|
||||
placeholder="Link"
|
||||
type="text"
|
||||
value={data.posting.link}
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Link to flyer (optional)
|
||||
<input
|
||||
type="text"
|
||||
name="flyerLink"
|
||||
id="flyerLink"
|
||||
placeholder="Flyer link"
|
||||
value={data.posting.flyerLink}
|
||||
class="w-full rounded font-normal"
|
||||
id="flyerLink"
|
||||
name="flyerLink"
|
||||
placeholder="Flyer link"
|
||||
type="text"
|
||||
value={data.posting.flyerLink}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -123,20 +123,22 @@
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button
|
||||
class="dull-primary-bg-color mb-4 mt-2 rounded px-2 py-1"
|
||||
formaction="?/submit"
|
||||
type="submit"
|
||||
formaction="?/submit">Save posting</button
|
||||
>
|
||||
>Save posting
|
||||
</button>
|
||||
<button
|
||||
class="danger-bg-color mb-4 mt-2 rounded px-2 py-1"
|
||||
onclick={openConfirm}
|
||||
type="button"
|
||||
onclick={openConfirm}>Delete posting</button
|
||||
>
|
||||
>Delete posting
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<form id="deleteConfirmModal" method="POST" class="modal">
|
||||
<form class="modal" id="deleteConfirmModal" method="POST">
|
||||
<div class="modal-content">
|
||||
<div class="mb-2 inline-flex w-full justify-between">
|
||||
<h2 class="font-semibold">Are you sure?</h2>
|
||||
@ -147,14 +149,16 @@
|
||||
<div class="mt-4 flex justify-between">
|
||||
<button
|
||||
class="danger-bg-color rounded px-2 py-1"
|
||||
formaction="?/delete&id={data.posting.id}"
|
||||
type="submit"
|
||||
formaction="?/delete&id={data.posting.id}">Delete posting</button
|
||||
>
|
||||
>Delete posting
|
||||
</button>
|
||||
<button
|
||||
class="separator-borders bg-color rounded px-2 py-1"
|
||||
onclick={closeConfirm}
|
||||
type="button"
|
||||
onclick={closeConfirm}>Cancel</button
|
||||
>
|
||||
>Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
<div class="bottom-border flex place-content-between">
|
||||
<div class="p-3 font-semibold">Create new posting</div>
|
||||
</div>
|
||||
<form method="POST" class="px-4" autocomplete="off" use:enhance>
|
||||
<form autocomplete="off" class="px-4" method="POST" use:enhance>
|
||||
{#if !userState.companyId}
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Company ID <span class="text-red-500">*</span>
|
||||
@ -29,39 +29,39 @@
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Title <span class="text-red-500">*</span>
|
||||
<input
|
||||
type="text"
|
||||
name="title"
|
||||
id="title"
|
||||
placeholder="Title"
|
||||
class="w-full rounded font-normal"
|
||||
id="title"
|
||||
name="title"
|
||||
placeholder="Title"
|
||||
required
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Description <span class="text-red-500">*</span>
|
||||
<textarea
|
||||
name="description"
|
||||
id="description"
|
||||
rows="4"
|
||||
placeholder="Description"
|
||||
class="w-full rounded font-normal"
|
||||
id="description"
|
||||
name="description"
|
||||
placeholder="Description"
|
||||
required
|
||||
rows="4"
|
||||
></textarea>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Address <span class="text-red-500">*</span>
|
||||
<input
|
||||
type="text"
|
||||
name="address"
|
||||
id="address"
|
||||
placeholder="Address"
|
||||
class="w-full rounded font-normal"
|
||||
id="address"
|
||||
name="address"
|
||||
placeholder="Address"
|
||||
required
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
<label for="employmentType">Employment type <span class="text-red-500">*</span></label>
|
||||
<select name="employmentType" id="employmentType" class="w-full rounded font-normal">
|
||||
<select class="w-full rounded font-normal" id="employmentType" name="employmentType">
|
||||
<option value="full_time">Full time</option>
|
||||
<option value="part_time">Part time</option>
|
||||
<option value="internship">Internship</option>
|
||||
@ -70,31 +70,31 @@
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Wage (optional)
|
||||
<input
|
||||
type="text"
|
||||
name="wage"
|
||||
id="wage"
|
||||
placeholder="Wage"
|
||||
class="w-full rounded font-normal"
|
||||
id="wage"
|
||||
name="wage"
|
||||
placeholder="Wage"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Link to external posting information (optional)
|
||||
<input
|
||||
type="text"
|
||||
name="link"
|
||||
id="link"
|
||||
placeholder="Link"
|
||||
class="w-full rounded font-normal"
|
||||
id="link"
|
||||
name="link"
|
||||
placeholder="Link"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Link to flyer (optional)
|
||||
<input
|
||||
type="text"
|
||||
name="flyerLink"
|
||||
id="flyerLink"
|
||||
placeholder="Flyer link"
|
||||
class="w-full rounded font-normal"
|
||||
id="flyerLink"
|
||||
name="flyerLink"
|
||||
placeholder="Flyer link"
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -103,9 +103,10 @@
|
||||
{/if}
|
||||
<button
|
||||
class="dull-primary-bg-color mb-4 mt-6 rounded px-2 py-1"
|
||||
formaction="?/submit"
|
||||
type="submit"
|
||||
formaction="?/submit">Create posting</button
|
||||
>
|
||||
>Create posting
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import * as dotenv from 'dotenv';
|
||||
import { type Actions, type Cookies, fail, redirect } from '@sveltejs/kit';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { type Actions, fail, redirect } from '@sveltejs/kit';
|
||||
import { createUser } from '$lib/db/index.server';
|
||||
|
||||
import { setJWT } from '$lib/shared.server';
|
||||
|
||||
@ -21,85 +21,85 @@
|
||||
<div class="elevated separator-borders bg content mb-4 rounded-md p-8">
|
||||
<h1 class="text-weight-semibold mb-4 text-center">Register</h1>
|
||||
<p>Create your account. Its free and only takes a minute!</p>
|
||||
<form method="POST" class="arrange-vertically" use:enhance>
|
||||
<form class="arrange-vertically" method="POST" use:enhance>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Username <span class="text-red-500">*</span>
|
||||
<input
|
||||
type="text"
|
||||
name="username"
|
||||
id="username"
|
||||
placeholder="Username"
|
||||
class="input-field w-full font-normal"
|
||||
id="username"
|
||||
name="username"
|
||||
placeholder="Username"
|
||||
required
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<div class="relative mt-4 text-sm font-semibold">
|
||||
Password <span class="text-red-500">*</span>
|
||||
<input
|
||||
type="password"
|
||||
class="input-field w-full font-normal"
|
||||
placeholder="Password"
|
||||
name="password"
|
||||
placeholder="Password"
|
||||
required
|
||||
type="password"
|
||||
/>
|
||||
</div>
|
||||
<div class="relative mt-4 text-sm font-semibold">
|
||||
Confirm password <span class="text-red-500">*</span>
|
||||
<input
|
||||
type="password"
|
||||
class="input-field w-full font-normal"
|
||||
placeholder="Password"
|
||||
name="confirmPassword"
|
||||
placeholder="Password"
|
||||
required
|
||||
type="password"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Full name <span class="text-red-500">*</span>
|
||||
<input
|
||||
type="text"
|
||||
name="fullName"
|
||||
id="fullName"
|
||||
placeholder="Full name"
|
||||
class="input-field w-full font-normal"
|
||||
id="fullName"
|
||||
name="fullName"
|
||||
placeholder="Full name"
|
||||
required
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Email <span class="text-red-500">*</span>
|
||||
<input
|
||||
type="text"
|
||||
name="email"
|
||||
id="email"
|
||||
placeholder="Email"
|
||||
class="input-field w-full font-normal"
|
||||
id="email"
|
||||
name="email"
|
||||
placeholder="Email"
|
||||
required
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<div class="mt-4 text-sm font-semibold">
|
||||
Phone (optional)
|
||||
<input
|
||||
type="tel"
|
||||
name="phone"
|
||||
id="phone"
|
||||
placeholder="Phone"
|
||||
class="w-full rounded font-normal"
|
||||
id="phone"
|
||||
name="phone"
|
||||
pattern="([0-9]\{3}) [0-9]\{3}-[0-9]\{3}"
|
||||
placeholder="Phone"
|
||||
type="tel"
|
||||
/>
|
||||
</div>
|
||||
<div class="relative mt-4 text-sm font-semibold">
|
||||
<label for="companyCode"> Company code (optional) </label>
|
||||
<div class="relative">
|
||||
<input
|
||||
type="text"
|
||||
name="companyCode"
|
||||
id="companyCode"
|
||||
placeholder="Company code"
|
||||
class="input-field w-full pr-10 font-normal"
|
||||
id="companyCode"
|
||||
name="companyCode"
|
||||
placeholder="Company code"
|
||||
type="text"
|
||||
/>
|
||||
<a
|
||||
type="button"
|
||||
href="/info#company-codes"
|
||||
class="hyperlink-color tooltip absolute inset-y-0 right-2 flex items-center"
|
||||
href="/info#company-codes"
|
||||
type="button"
|
||||
>
|
||||
<span class="material-symbols-outlined">info</span><span
|
||||
class="tooltip-text font-sans text-sm font-normal">About company codes</span
|
||||
@ -114,10 +114,11 @@
|
||||
|
||||
<button
|
||||
class="primary-bg-color mt-8 w-full rounded px-2 py-2"
|
||||
formaction="?/register"
|
||||
type="submit"
|
||||
formaction="?/register">Create account</button
|
||||
>
|
||||
<a href="/signin" class="low-emphasis-text-button mt-2">I already have an account.</a>
|
||||
>Create account
|
||||
</button>
|
||||
<a class="low-emphasis-text-button mt-2" href="/signin">I already have an account.</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -31,30 +31,30 @@
|
||||
<div class="signin-container place-items-center pt-8">
|
||||
<div class="separator-borders elevated content rounded-md p-8">
|
||||
<h1 class="text-weight-semibold mb-4 text-center">Welcome Back!</h1>
|
||||
<form method="POST" class="arrange-vertically" use:enhance>
|
||||
<form class="arrange-vertically" method="POST" use:enhance>
|
||||
<div class="bg-color my-2 rounded">
|
||||
<input
|
||||
class="input-field w-full"
|
||||
type="text"
|
||||
placeholder="Username"
|
||||
name="username"
|
||||
placeholder="Username"
|
||||
required
|
||||
type="text"
|
||||
/>
|
||||
</div>
|
||||
<div class="relative w-full">
|
||||
<div class="bg-color mt-4 rounded">
|
||||
<input
|
||||
type={passwordVisible ? 'text' : 'password'}
|
||||
class="input-field w-full pr-10"
|
||||
placeholder="Password"
|
||||
name="password"
|
||||
placeholder="Password"
|
||||
required
|
||||
type={passwordVisible ? 'text' : 'password'}
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
onclick={showPassword}
|
||||
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
|
||||
@ -68,10 +68,11 @@
|
||||
|
||||
<button
|
||||
class="primary-bg-color mt-8 w-full rounded px-2 py-2"
|
||||
formaction="?/signin"
|
||||
type="submit"
|
||||
formaction="?/signin">Sign In</button
|
||||
>
|
||||
<a href="/register" class="low-emphasis-text-button mt-2"
|
||||
>Sign In
|
||||
</button>
|
||||
<a class="low-emphasis-text-button mt-2" href="/register"
|
||||
>Don't have an account? Register here.</a
|
||||
>
|
||||
</form>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user