finalized application acceptance system and started making types shared across front and backend
This commit is contained in:
@@ -2,23 +2,22 @@ const express = require('express');
|
|||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
import pool from '../db';
|
import pool from '../db';
|
||||||
|
import { approveApplication, createApplication, getApplicationByID, getApplicationComments, getApplicationList, getMemberApplication } from '../services/applicationService';
|
||||||
|
import { MemberState, setUserState } from '../services/memberService';
|
||||||
|
import { getRankByName, insertMemberRank } from '../services/rankService';
|
||||||
|
import { ApplicationFull, CommentRow } from "@app/shared/types/application"
|
||||||
|
import { assignUserToStatus } from '../services/statusService';
|
||||||
|
|
||||||
// POST /application
|
// POST /application
|
||||||
router.post('/', async (req, res) => {
|
router.post('/', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const App = req.body?.App || {};
|
const App = req.body?.App || {};
|
||||||
|
const memberID = req.user.id;
|
||||||
|
|
||||||
// TODO: replace with current user ID
|
|
||||||
const memberId = 1;
|
|
||||||
|
|
||||||
const sql = `INSERT INTO applications (member_id, app_version, app_data) VALUES (?, ?, ?);`;
|
|
||||||
const appVersion = 1;
|
const appVersion = 1;
|
||||||
|
|
||||||
const params = [memberId, appVersion, JSON.stringify(App)]
|
createApplication(memberID, appVersion, JSON.stringify(App))
|
||||||
|
setUserState(memberID, MemberState.Applicant);
|
||||||
console.log(params)
|
|
||||||
|
|
||||||
await pool.query(sql, params);
|
|
||||||
|
|
||||||
res.sendStatus(201);
|
res.sendStatus(201);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -30,18 +29,7 @@ router.post('/', async (req, res) => {
|
|||||||
// GET /application/all
|
// GET /application/all
|
||||||
router.get('/all', async (req, res) => {
|
router.get('/all', async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const sql = `SELECT
|
const rows = await getApplicationList();
|
||||||
member.name AS member_name,
|
|
||||||
app.id,
|
|
||||||
app.member_id,
|
|
||||||
app.submitted_at,
|
|
||||||
app.app_status
|
|
||||||
FROM applications AS app
|
|
||||||
LEFT JOIN members AS member
|
|
||||||
ON member.id = app.member_id;`
|
|
||||||
|
|
||||||
const rows = await pool.query(sql);
|
|
||||||
|
|
||||||
res.status(200).json(rows);
|
res.status(200).json(rows);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
@@ -49,47 +37,35 @@ router.get('/all', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/me', async (req, res) => {
|
||||||
|
let userID = req.user.id;
|
||||||
|
|
||||||
|
console.log("application/me")
|
||||||
|
|
||||||
|
let app = getMemberApplication(userID);
|
||||||
|
console.log(app);
|
||||||
|
})
|
||||||
|
|
||||||
// GET /application/:id
|
// GET /application/:id
|
||||||
router.get('/:id', async (req, res) => {
|
router.get('/:id', async (req, res) => {
|
||||||
let appID = req.params.id;
|
let appID = req.params.id;
|
||||||
|
|
||||||
//TODO: Replace with real user Authorization and whatnot
|
|
||||||
// if the application is not "me" and I am not a recruiter, deny access to the application (return 403 or whatever)
|
|
||||||
if (appID === "me")
|
|
||||||
appID = 2;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const conn = await pool.getConnection()
|
const conn = await pool.getConnection()
|
||||||
|
|
||||||
const application = await conn.query(
|
const application = await getApplicationByID(appID);
|
||||||
`SELECT app.*,
|
|
||||||
member.name AS member_name
|
|
||||||
FROM applications AS app
|
|
||||||
INNER JOIN members AS member ON member.id = app.member_id
|
|
||||||
WHERE app.id = ?;`,
|
|
||||||
[appID]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!Array.isArray(application) || application.length === 0) {
|
if (!Array.isArray(application) || application.length === 0) {
|
||||||
conn.release();
|
conn.release();
|
||||||
return res.status(204).json("Application Not Found");
|
return res.status(204).json("Application Not Found");
|
||||||
}
|
}
|
||||||
|
|
||||||
const comments = await conn.query(`SELECT app.id AS comment_id,
|
const comments: CommentRow[] = await getApplicationComments(appID);
|
||||||
app.post_content,
|
|
||||||
app.poster_id,
|
|
||||||
app.post_time,
|
|
||||||
app.last_modified,
|
|
||||||
member.name AS poster_name
|
|
||||||
FROM application_comments AS app
|
|
||||||
INNER JOIN members AS member ON member.id = app.poster_id
|
|
||||||
WHERE app.application_id = ?;`,
|
|
||||||
[appID]);
|
|
||||||
|
|
||||||
conn.release()
|
conn.release()
|
||||||
|
|
||||||
const output = {
|
const output: ApplicationFull = {
|
||||||
application: application[0],
|
application,
|
||||||
comments,
|
comments,
|
||||||
}
|
}
|
||||||
return res.status(200).json(output);
|
return res.status(200).json(output);
|
||||||
@@ -104,26 +80,27 @@ router.get('/:id', async (req, res) => {
|
|||||||
router.post('/approve/:id', async (req, res) => {
|
router.post('/approve/:id', async (req, res) => {
|
||||||
const appID = req.params.id;
|
const appID = req.params.id;
|
||||||
|
|
||||||
const sql = `
|
|
||||||
UPDATE applications
|
|
||||||
SET approved_at = NOW()
|
|
||||||
WHERE id = ?
|
|
||||||
AND approved_at IS NULL
|
|
||||||
AND denied_at IS NULL
|
|
||||||
`;
|
|
||||||
try {
|
try {
|
||||||
const result = await pool.execute(sql, appID);
|
const app = await getApplicationByID(appID);
|
||||||
|
const result = await approveApplication(appID);
|
||||||
|
|
||||||
console.log(result);
|
console.log("START");
|
||||||
|
console.log(app, result);
|
||||||
|
|
||||||
if (result.affectedRows === 0) {
|
//guard against failures
|
||||||
res.status(400).json('Something went wrong approving the application');
|
if (result.affectedRows != 1) {
|
||||||
|
throw new Error("Something went wrong approving the application");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.affectedRows == 1) {
|
console.log(app.member_id);
|
||||||
res.sendStatus(200);
|
//update user profile
|
||||||
}
|
await setUserState(app.member_id, MemberState.Member);
|
||||||
|
|
||||||
|
let nextRank = await getRankByName('Recruit')
|
||||||
|
await insertMemberRank(app.member_id, nextRank.id);
|
||||||
|
//assign user to "pending basic"
|
||||||
|
await assignUserToStatus(app.member_id, 1);
|
||||||
|
res.sendStatus(200);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Approve failed:', err);
|
console.error('Approve failed:', err);
|
||||||
res.status(500).json({ error: 'Failed to approve application' });
|
res.status(500).json({ error: 'Failed to approve application' });
|
||||||
@@ -7,7 +7,7 @@ const { getAllRanks, insertMemberRank } = require('../services/rankService')
|
|||||||
ur.post('/', async (req, res) => {3
|
ur.post('/', async (req, res) => {3
|
||||||
try {
|
try {
|
||||||
const change = req.body?.change;
|
const change = req.body?.change;
|
||||||
await insertMemberRank(change);
|
await insertMemberRank(change.member_id, change.rank_id, change.date);
|
||||||
|
|
||||||
res.sendStatus(201);
|
res.sendStatus(201);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
71
api/src/services/applicationService.ts
Normal file
71
api/src/services/applicationService.ts
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
import { ApplicationListRow, ApplicationRow, CommentRow } from "@app/shared/types/application";
|
||||||
|
import pool from "../db";
|
||||||
|
|
||||||
|
export async function createApplication(memberID: number, appVersion: number, app: string) {
|
||||||
|
const sql = `INSERT INTO applications (member_id, app_version, app_data) VALUES (?, ?, ?);`;
|
||||||
|
const params = [memberID, appVersion, JSON.stringify(app)]
|
||||||
|
return await pool.query(sql, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getMemberApplication(memberID: number): Promise<ApplicationRow> {
|
||||||
|
const sql = `SELECT app.*,
|
||||||
|
member.name AS member_name
|
||||||
|
FROM applications AS app
|
||||||
|
INNER JOIN members AS member ON member.id = app.member_id
|
||||||
|
WHERE app.member_id = ?;`;
|
||||||
|
|
||||||
|
let app: ApplicationRow[] = await pool.query(sql, [memberID]);
|
||||||
|
return app[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getApplicationByID(appID: number): Promise<ApplicationRow> {
|
||||||
|
const sql =
|
||||||
|
`SELECT app.*,
|
||||||
|
member.name AS member_name
|
||||||
|
FROM applications AS app
|
||||||
|
INNER JOIN members AS member ON member.id = app.member_id
|
||||||
|
WHERE app.id = ?;`;
|
||||||
|
let app: ApplicationRow[] = await pool.query(sql, [appID]);
|
||||||
|
return app[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getApplicationList(): Promise<ApplicationListRow[]> {
|
||||||
|
const sql = `SELECT
|
||||||
|
member.name AS member_name,
|
||||||
|
app.id,
|
||||||
|
app.member_id,
|
||||||
|
app.submitted_at,
|
||||||
|
app.app_status
|
||||||
|
FROM applications AS app
|
||||||
|
LEFT JOIN members AS member
|
||||||
|
ON member.id = app.member_id;`
|
||||||
|
|
||||||
|
const rows: ApplicationListRow[] = await pool.query(sql);
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function approveApplication(id) {
|
||||||
|
const sql = `
|
||||||
|
UPDATE applications
|
||||||
|
SET approved_at = NOW()
|
||||||
|
WHERE id = ?
|
||||||
|
AND approved_at IS NULL
|
||||||
|
AND denied_at IS NULL
|
||||||
|
`;
|
||||||
|
|
||||||
|
const result = await pool.execute(sql, id);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getApplicationComments(appID: number): Promise<CommentRow[]> {
|
||||||
|
return await pool.query(`SELECT app.id AS comment_id,
|
||||||
|
app.post_content,
|
||||||
|
app.poster_id,
|
||||||
|
app.post_time,
|
||||||
|
app.last_modified,
|
||||||
|
member.name AS poster_name
|
||||||
|
FROM application_comments AS app
|
||||||
|
INNER JOIN members AS member ON member.id = app.poster_id
|
||||||
|
WHERE app.application_id = ?;`,
|
||||||
|
[appID]);
|
||||||
|
}
|
||||||
@@ -1,8 +1,23 @@
|
|||||||
import pool from "../db";
|
import pool from "../db";
|
||||||
|
|
||||||
|
export enum MemberState {
|
||||||
|
Guest = "guest",
|
||||||
|
Applicant = "applicant",
|
||||||
|
Member = "member",
|
||||||
|
Retired = "retired",
|
||||||
|
Banned = "banned",
|
||||||
|
Denied = "denied"
|
||||||
|
}
|
||||||
|
|
||||||
export async function getUserData(userID: number) {
|
export async function getUserData(userID: number) {
|
||||||
const sql = `SELECT * FROM members WHERE id = ?`;
|
const sql = `SELECT * FROM members WHERE id = ?`;
|
||||||
const res = await pool.query(sql, [userID]);
|
const res = await pool.query(sql, [userID]);
|
||||||
return res[0] ?? null;
|
return res[0] ?? null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function setUserState(userID: number, state: MemberState) {
|
||||||
|
const sql = `UPDATE members
|
||||||
|
SET state = ?
|
||||||
|
WHERE id = ?;`;
|
||||||
|
return await pool.query(sql, [state, userID]);
|
||||||
|
}
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
import pool from "../db";
|
|
||||||
|
|
||||||
async function getAllRanks() {
|
|
||||||
const rows = await pool.query(
|
|
||||||
'SELECT id, name, short_name, sort_id FROM ranks;'
|
|
||||||
);
|
|
||||||
return rows;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function insertMemberRank(change) {
|
|
||||||
const sql = `
|
|
||||||
INSERT INTO members_ranks (member_id, rank_id, event_date)
|
|
||||||
VALUES (?, ?, ?);
|
|
||||||
`;
|
|
||||||
const params = [change.member_id, change.rank_id, change.date];
|
|
||||||
await pool.query(sql, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
getAllRanks,
|
|
||||||
insertMemberRank
|
|
||||||
};
|
|
||||||
32
api/src/services/rankService.ts
Normal file
32
api/src/services/rankService.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import pool from "../db";
|
||||||
|
|
||||||
|
export async function getAllRanks() {
|
||||||
|
const rows = await pool.query(
|
||||||
|
'SELECT id, name, short_name, sort_id FROM ranks;'
|
||||||
|
);
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getRankByName(name: string) {
|
||||||
|
const rows = await pool.query(`SELECT id, name, short_name, sort_id FROM ranks WHERE name = ?`, [name]);
|
||||||
|
|
||||||
|
if (rows.length === 0)
|
||||||
|
throw new Error("Could not find rank: " + name);
|
||||||
|
|
||||||
|
return rows[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function insertMemberRank(member_id: number, rank_id: number, date: Date): Promise<void>;
|
||||||
|
export async function insertMemberRank(member_id: number, rank_id: number): Promise<void>;
|
||||||
|
|
||||||
|
export async function insertMemberRank(member_id: number, rank_id: number, date?: Date): Promise<void> {
|
||||||
|
const sql = date
|
||||||
|
? `INSERT INTO members_ranks (member_id, rank_id, event_date) VALUES (?, ?, ?);`
|
||||||
|
: `INSERT INTO members_ranks (member_id, rank_id, event_date) VALUES (?, ?, NOW());`;
|
||||||
|
|
||||||
|
const params = date
|
||||||
|
? [member_id, rank_id, date]
|
||||||
|
: [member_id, rank_id];
|
||||||
|
|
||||||
|
await pool.query(sql, params);
|
||||||
|
}
|
||||||
6
api/src/services/statusService.ts
Normal file
6
api/src/services/statusService.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import pool from "../db"
|
||||||
|
|
||||||
|
export async function assignUserToStatus(userID: number, statusID: number) {
|
||||||
|
const sql = `INSERT INTO members_statuses (member_id, status_id, event_date) VALUES (?, ?, NOW())`
|
||||||
|
await pool.execute(sql, [userID, statusID]);
|
||||||
|
}
|
||||||
@@ -6,7 +6,10 @@
|
|||||||
"types": [
|
"types": [
|
||||||
"node",
|
"node",
|
||||||
"express"
|
"express"
|
||||||
]
|
],
|
||||||
|
"paths": {
|
||||||
|
"@app/shared/*": ["../shared/*"]
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"./src/**/*"
|
"./src/**/*"
|
||||||
|
|||||||
6
shared/package.json
Normal file
6
shared/package.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"name": "@app/shared",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.ts",
|
||||||
|
"type": "module"
|
||||||
|
}
|
||||||
57
shared/types/application.ts
Normal file
57
shared/types/application.ts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
export interface ApplicationData {
|
||||||
|
dob: string;
|
||||||
|
name: string;
|
||||||
|
playtime: number;
|
||||||
|
hobbies: string;
|
||||||
|
military: boolean;
|
||||||
|
communities: string;
|
||||||
|
joinReason: string;
|
||||||
|
milsimAttraction: string;
|
||||||
|
referral: string;
|
||||||
|
steamProfile: string;
|
||||||
|
timezone: string;
|
||||||
|
canAttendSaturday: boolean;
|
||||||
|
interests: string;
|
||||||
|
aknowledgeRules: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApplicationRow {
|
||||||
|
id: number;
|
||||||
|
member_id: number;
|
||||||
|
app_version: number;
|
||||||
|
app_data: ApplicationData;
|
||||||
|
|
||||||
|
submitted_at: string; // ISO datetime from DB (e.g., "2025-08-25T18:04:29.000Z")
|
||||||
|
updated_at: string | null;
|
||||||
|
approved_at: string | null;
|
||||||
|
denied_at: string | null;
|
||||||
|
|
||||||
|
app_status: Status; // generated column
|
||||||
|
decision_at: string | null; // generated column
|
||||||
|
|
||||||
|
// present when you join members (e.g., SELECT a.*, m.name AS member_name)
|
||||||
|
member_name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CommentRow {
|
||||||
|
comment_id: number;
|
||||||
|
post_content: string;
|
||||||
|
poster_id: number;
|
||||||
|
post_time: string;
|
||||||
|
last_modified: string | null;
|
||||||
|
poster_name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ApplicationFull {
|
||||||
|
application: ApplicationRow;
|
||||||
|
comments: CommentRow[];
|
||||||
|
}
|
||||||
|
|
||||||
|
//for get all applications route
|
||||||
|
export interface ApplicationListRow {
|
||||||
|
id: number;
|
||||||
|
member_id: number;
|
||||||
|
member_name: string | null; // because LEFT JOIN means it might be null
|
||||||
|
submitted_at: Date;
|
||||||
|
app_status: string; // or enum if you have one
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": ["./src/*"],
|
||||||
|
"@shared": ["../shared/*"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules", "dist"]
|
"exclude": ["node_modules", "dist"]
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ export interface ApplicationData {
|
|||||||
aknowledgeRules: boolean;
|
aknowledgeRules: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//reflects how applications are stored in the database
|
||||||
export interface ApplicationRow {
|
export interface ApplicationRow {
|
||||||
id: number;
|
id: number;
|
||||||
member_id: number;
|
member_id: number;
|
||||||
@@ -43,7 +44,7 @@ export interface ApplicationRow {
|
|||||||
approved_at: string | null;
|
approved_at: string | null;
|
||||||
denied_at: string | null;
|
denied_at: string | null;
|
||||||
|
|
||||||
app_status: Status; // generated column
|
app_status: ApplicationStatus; // generated column
|
||||||
decision_at: string | null; // generated column
|
decision_at: string | null; // generated column
|
||||||
|
|
||||||
// present when you join members (e.g., SELECT a.*, m.name AS member_name)
|
// present when you join members (e.g., SELECT a.*, m.name AS member_name)
|
||||||
@@ -64,7 +65,7 @@ export interface ApplicationFull {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export enum Status {
|
export enum ApplicationStatus {
|
||||||
Pending = "Pending",
|
Pending = "Pending",
|
||||||
Accepted = "Accepted",
|
Accepted = "Accepted",
|
||||||
Denied = "Denied",
|
Denied = "Denied",
|
||||||
@@ -90,6 +91,7 @@ export async function postApplication(val: any) {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify(out),
|
body: JSON.stringify(out),
|
||||||
|
credentials: 'include',
|
||||||
})
|
})
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -109,7 +111,7 @@ export async function postChatMessage(message: any, post_id: number) {
|
|||||||
return await response.json();
|
return await response.json();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getAllApplications() {
|
export async function getAllApplications(): Promise<ApplicationFull> {
|
||||||
const res = await fetch(`${addr}/application/all`)
|
const res = await fetch(`${addr}/application/all`)
|
||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
|
|||||||
@@ -59,9 +59,13 @@ async function onSubmit(val: any) {
|
|||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (props.data !== null) {
|
if (props.data !== null) {
|
||||||
initialValues.value = { ...props.data }
|
const parsed = typeof props.data === "string"
|
||||||
|
? JSON.parse(props.data)
|
||||||
|
: props.data;
|
||||||
|
|
||||||
|
initialValues.value = { ...parsed };
|
||||||
} else {
|
} else {
|
||||||
initialValues.value = { ...fallbackInitials }
|
initialValues.value = { ...fallbackInitials };
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -76,8 +80,7 @@ onMounted(() => {
|
|||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>What is your date of birth?</FormLabel>
|
<FormLabel>What is your date of birth?</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<DateInput :model-value="(value as string) ?? ''" :disabled="readOnly"
|
<DateInput :model-value="(value as string) ?? ''" :disabled="readOnly" @update:model-value="handleChange" />
|
||||||
@update:model-value="handleChange" />
|
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import ApplicationChat from '@/components/application/ApplicationChat.vue';
|
import ApplicationChat from '@/components/application/ApplicationChat.vue';
|
||||||
import ApplicationForm from '@/components/application/ApplicationForm.vue';
|
import ApplicationForm from '@/components/application/ApplicationForm.vue';
|
||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import { ApplicationData, approveApplication, denyApplication, loadApplication, postApplication, postChatMessage, Status } from '@/api/application';
|
import { ApplicationData, approveApplication, denyApplication, loadApplication, postApplication, postChatMessage, ApplicationStatus } from '@/api/application';
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import Button from '@/components/ui/button/Button.vue';
|
import Button from '@/components/ui/button/Button.vue';
|
||||||
import { CheckIcon, XIcon } from 'lucide-vue-next';
|
import { CheckIcon, XIcon } from 'lucide-vue-next';
|
||||||
@@ -12,7 +12,7 @@ const appID = ref<number | null>(null);
|
|||||||
const chatData = ref<object[]>([])
|
const chatData = ref<object[]>([])
|
||||||
const readOnly = ref<boolean>(false);
|
const readOnly = ref<boolean>(false);
|
||||||
const newApp = ref<boolean>(null);
|
const newApp = ref<boolean>(null);
|
||||||
const status = ref<Status>(null);
|
const status = ref<ApplicationStatus>(null);
|
||||||
const decisionDate = ref<Date | null>(null);
|
const decisionDate = ref<Date | null>(null);
|
||||||
const submitDate = ref<Date | null>(null);
|
const submitDate = ref<Date | null>(null);
|
||||||
const loading = ref<boolean>(true);
|
const loading = ref<boolean>(true);
|
||||||
@@ -54,6 +54,7 @@ async function postComment(comment) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function postApp(appData) {
|
async function postApp(appData) {
|
||||||
|
console.log("test")
|
||||||
const res = await postApplication(appData);
|
const res = await postApplication(appData);
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
readOnly.value = true;
|
readOnly.value = true;
|
||||||
@@ -89,11 +90,11 @@ async function handleDeny(id) {
|
|||||||
<div>
|
<div>
|
||||||
<h3 class="text-right" :class="[
|
<h3 class="text-right" :class="[
|
||||||
'font-semibold',
|
'font-semibold',
|
||||||
status === Status.Pending && 'text-yellow-500',
|
status === ApplicationStatus.Pending && 'text-yellow-500',
|
||||||
status === Status.Accepted && 'text-green-500',
|
status === ApplicationStatus.Accepted && 'text-green-500',
|
||||||
status === Status.Denied && 'text-red-500'
|
status === ApplicationStatus.Denied && 'text-red-500'
|
||||||
]">{{ status }}</h3>
|
]">{{ status }}</h3>
|
||||||
<p v-if="status != Status.Pending" class="text-muted-foreground">{{ status }}: {{
|
<p v-if="status != ApplicationStatus.Pending" class="text-muted-foreground">{{ status }}: {{
|
||||||
decisionDate.toLocaleString("en-US", {
|
decisionDate.toLocaleString("en-US", {
|
||||||
year: "numeric",
|
year: "numeric",
|
||||||
month: "long",
|
month: "long",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { getAllApplications, approveApplication, denyApplication, Status } from '@/api/application';
|
import { getAllApplications, approveApplication, denyApplication, ApplicationStatus } from '@/api/application';
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
TableBody,
|
TableBody,
|
||||||
@@ -87,7 +87,7 @@ onMounted(async () => {
|
|||||||
<TableCell :title="formatExact(app.submitted_at)">
|
<TableCell :title="formatExact(app.submitted_at)">
|
||||||
{{ formatAgo(app.submitted_at) }}
|
{{ formatAgo(app.submitted_at) }}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell v-if="app.app_status === Status.Pending" class="inline-flex items-end gap-2">
|
<TableCell v-if="app.app_status === ApplicationStatus.Pending" class="inline-flex items-end gap-2">
|
||||||
<Button variant="success" @click.stop="() => { handleApprove(app.id) }">
|
<Button variant="success" @click.stop="() => { handleApprove(app.id) }">
|
||||||
<CheckIcon></CheckIcon>
|
<CheckIcon></CheckIcon>
|
||||||
</Button>
|
</Button>
|
||||||
@@ -97,9 +97,9 @@ onMounted(async () => {
|
|||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell class="text-right font-semibold" :class="[
|
<TableCell class="text-right font-semibold" :class="[
|
||||||
,
|
,
|
||||||
app.app_status === Status.Pending && 'text-yellow-500',
|
app.app_status === ApplicationStatus.Pending && 'text-yellow-500',
|
||||||
app.app_status === Status.Accepted && 'text-green-500',
|
app.app_status === ApplicationStatus.Accepted && 'text-green-500',
|
||||||
app.app_status === Status.Denied && 'text-destructive'
|
app.app_status === ApplicationStatus.Denied && 'text-destructive'
|
||||||
]">{{ app.app_status }}</TableCell>
|
]">{{ app.app_status }}</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableBody>
|
</TableBody>
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ router.beforeEach(async (to) => {
|
|||||||
|
|
||||||
// Make sure user state is loaded before checking
|
// Make sure user state is loaded before checking
|
||||||
if (!user.loaded) {
|
if (!user.loaded) {
|
||||||
console.log('loaduser')
|
|
||||||
await user.loadUser();
|
await user.loadUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,12 +54,10 @@ router.beforeEach(async (to) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Must be a member
|
// // Must be a member
|
||||||
if (to.meta.memberOnly && user.state !== 'member') {
|
// if (to.meta.memberOnly && user.state !== 'member') {
|
||||||
return '/unauthorized'
|
// return '/unauthorized'
|
||||||
}
|
// }
|
||||||
|
|
||||||
console.log(!user.hasRole("Dev"));
|
|
||||||
|
|
||||||
// // Must have specific role
|
// // Must have specific role
|
||||||
// if (to.meta.roles && !user.hasRole('Dev') && !user.hasAnyRole(to.meta.roles)) {
|
// if (to.meta.roles && !user.hasRole('Dev') && !user.hasAnyRole(to.meta.roles)) {
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ export const useUserStore = defineStore('user', () => {
|
|||||||
|
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
console.log(data);
|
|
||||||
user.value = data;
|
user.value = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user