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