Merge pull request '100-recruitment-ui-fixes' (#101) from 100-recruitment-ui-fixes into main
All checks were successful
Continuous Integration / Update Development (push) Successful in 2m31s
All checks were successful
Continuous Integration / Update Development (push) Successful in 2m31s
Reviewed-on: #101
This commit was merged in pull request #101.
This commit is contained in:
@@ -155,21 +155,13 @@ router.post('/approve/:id', [requireLogin, requireRole("Recruiter")], async (req
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const app = await getApplicationByID(appID);
|
const app = await getApplicationByID(appID);
|
||||||
const result = await approveApplication(appID);
|
await approveApplication(appID, approved_by);
|
||||||
|
|
||||||
//guard against failures
|
|
||||||
if (result.affectedRows != 1) {
|
|
||||||
throw new Error("Something went wrong approving the application");
|
|
||||||
}
|
|
||||||
|
|
||||||
//update user profile
|
//update user profile
|
||||||
await setUserState(app.member_id, MemberState.Member);
|
await setUserState(app.member_id, MemberState.Member);
|
||||||
|
|
||||||
await pool.query('CALL sp_accept_new_recruit_validation(?, ?, ?, ?)', [Number(process.env.CONFIG_ID), app.member_id, approved_by, approved_by])
|
await pool.query('CALL sp_accept_new_recruit_validation(?, ?, ?, ?)', [Number(process.env.CONFIG_ID), app.member_id, approved_by, approved_by])
|
||||||
// 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);
|
res.sendStatus(200);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Approve failed:', err);
|
console.error('Approve failed:', err);
|
||||||
@@ -178,12 +170,13 @@ router.post('/approve/:id', [requireLogin, requireRole("Recruiter")], async (req
|
|||||||
});
|
});
|
||||||
|
|
||||||
// POST /application/deny/:id
|
// POST /application/deny/:id
|
||||||
router.post('/deny/:id', [requireLogin, requireRole("Recruiter")], async (req, res) => {
|
router.post('/deny/:id', [requireLogin, requireRole("Recruiter")], async (req: Request, res: Response) => {
|
||||||
const appID = req.params.id;
|
const appID = Number(req.params.id);
|
||||||
|
const approver = Number(req.user.id);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const app = await getApplicationByID(appID);
|
const app = await getApplicationByID(appID);
|
||||||
await denyApplication(appID);
|
await denyApplication(appID, approver);
|
||||||
await setUserState(app.member_id, MemberState.Denied);
|
await setUserState(app.member_id, MemberState.Denied);
|
||||||
res.sendStatus(200);
|
res.sendStatus(200);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export async function getApplicationByID(appID: number): Promise<ApplicationRow>
|
|||||||
return app[0];
|
return app[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getApplicationList(): Promise<ApplicationListRow[]> {
|
export async function getApplicationList(page: number = 1, pageSize: number = 25): Promise<ApplicationListRow[]> {
|
||||||
const sql = `SELECT
|
const sql = `SELECT
|
||||||
member.name AS member_name,
|
member.name AS member_name,
|
||||||
app.id,
|
app.id,
|
||||||
@@ -40,9 +40,11 @@ export async function getApplicationList(): Promise<ApplicationListRow[]> {
|
|||||||
app.app_status
|
app.app_status
|
||||||
FROM applications AS app
|
FROM applications AS app
|
||||||
LEFT JOIN members AS member
|
LEFT JOIN members AS member
|
||||||
ON member.id = app.member_id;`
|
ON member.id = app.member_id
|
||||||
|
ORDER BY app.submitted_at DESC
|
||||||
|
LIMIT ? OFFSET ?;`
|
||||||
|
|
||||||
const rows: ApplicationListRow[] = await pool.query(sql);
|
const rows: ApplicationListRow[] = await pool.query(sql, [pageSize, page]);
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,30 +61,35 @@ export async function getAllMemberApplications(memberID: number): Promise<Applic
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export async function approveApplication(id: number) {
|
export async function approveApplication(id: number, approver: number) {
|
||||||
const sql = `
|
const sql = `
|
||||||
UPDATE applications
|
UPDATE applications
|
||||||
SET approved_at = NOW()
|
SET approved_at = NOW(), approved_by = ?
|
||||||
WHERE id = ?
|
WHERE id = ?
|
||||||
AND approved_at IS NULL
|
AND approved_at IS NULL
|
||||||
AND denied_at IS NULL
|
AND denied_at IS NULL
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const result = await pool.execute(sql, id);
|
const result = await pool.execute(sql, [approver, id]);
|
||||||
return result;
|
console.log(result);
|
||||||
|
if (result.affectedRows == 1) {
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
throw new Error(`"Something went wrong approving application with ID ${id}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function denyApplication(id: number) {
|
export async function denyApplication(id: number, approver: number) {
|
||||||
const sql = `
|
const sql = `
|
||||||
UPDATE applications
|
UPDATE applications
|
||||||
SET denied_at = NOW()
|
SET denied_at = NOW(), approved_by = ?
|
||||||
WHERE id = ?
|
WHERE id = ?
|
||||||
AND approved_at IS NULL
|
AND approved_at IS NULL
|
||||||
AND denied_at IS NULL
|
AND denied_at IS NULL
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const result = await pool.execute(sql, id);
|
const result = await pool.execute(sql, [approver, id]);
|
||||||
|
console.log(result);
|
||||||
if (result.affectedRows == 1) {
|
if (result.affectedRows == 1) {
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -94,16 +94,18 @@ export async function approveApplication(id: Number) {
|
|||||||
const res = await fetch(`${addr}/application/approve/${id}`, { method: 'POST', credentials: 'include' })
|
const res = await fetch(`${addr}/application/approve/${id}`, { method: 'POST', credentials: 'include' })
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
console.error("Something went wrong approving the application")
|
throw new Error("Something went wrong approving the application");
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function denyApplication(id: Number) {
|
export async function denyApplication(id: Number) {
|
||||||
const res = await fetch(`${addr}/application/deny/${id}`, { method: 'POST', credentials: 'include' })
|
const res = await fetch(`${addr}/application/deny/${id}`, { method: 'POST', credentials: 'include' })
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
console.error("Something went wrong denying the application")
|
throw new Error("Something went wrong denyting the application");
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function restartApplication() {
|
export async function restartApplication() {
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ watch(() => showCoC.value, async () => {
|
|||||||
<FormLabel>Have you ever served in the military?</FormLabel>
|
<FormLabel>Have you ever served in the military?</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<Checkbox :checked="value ?? false" @update:checked="handleChange" :disabled="readOnly" />
|
<Checkbox :model-value="value" @update:model-value="handleChange" :disabled="readOnly" />
|
||||||
<span>Yes (checked) / No (unchecked)</span>
|
<span>Yes (checked) / No (unchecked)</span>
|
||||||
</div>
|
</div>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|||||||
@@ -105,12 +105,21 @@ async function postApp(appData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleApprove(id) {
|
async function handleApprove(id) {
|
||||||
console.log("hi");
|
try {
|
||||||
await approveApplication(id);
|
await approveApplication(id);
|
||||||
|
loadData(await loadApplication(Number(route.params.id), true))
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleDeny(id) {
|
async function handleDeny(id) {
|
||||||
await denyApplication(id);
|
try {
|
||||||
|
await denyApplication(id);
|
||||||
|
loadData(await loadApplication(Number(route.params.id), true))
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -164,7 +173,8 @@ async function handleDeny(id) {
|
|||||||
</ApplicationForm>
|
</ApplicationForm>
|
||||||
<div v-if="!newApp" class="pb-15">
|
<div v-if="!newApp" class="pb-15">
|
||||||
<h3 class="scroll-m-20 text-2xl font-semibold tracking-tight mb-4">Discussion</h3>
|
<h3 class="scroll-m-20 text-2xl font-semibold tracking-tight mb-4">Discussion</h3>
|
||||||
<ApplicationChat :messages="chatData" @post="postComment" @post-internal="postCommentInternal" :admin-mode="finalMode === 'view-recruiter'">
|
<ApplicationChat :messages="chatData" @post="postComment" @post-internal="postCommentInternal"
|
||||||
|
:admin-mode="finalMode === 'view-recruiter'">
|
||||||
</ApplicationChat>
|
</ApplicationChat>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
TableRow,
|
TableRow,
|
||||||
} from '@/components/ui/table'
|
} from '@/components/ui/table'
|
||||||
import Button from '@/components/ui/button/Button.vue';
|
import Button from '@/components/ui/button/Button.vue';
|
||||||
import { onMounted, ref, watch } from 'vue';
|
import { computed, onMounted, ref, watch } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
import { CheckIcon, XIcon } from 'lucide-vue-next';
|
import { CheckIcon, XIcon } from 'lucide-vue-next';
|
||||||
import Application from './Application.vue';
|
import Application from './Application.vue';
|
||||||
@@ -52,36 +52,26 @@ function formatExact(iso) {
|
|||||||
return isNaN(d) ? '' : exactFmt.format(d)
|
return isNaN(d) ? '' : exactFmt.format(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleApprove(id) {
|
|
||||||
await approveApplication(id);
|
|
||||||
appList.value = await getAllApplications();
|
|
||||||
}
|
|
||||||
|
|
||||||
async function handleDeny(id) {
|
|
||||||
await denyApplication(id);
|
|
||||||
appList.value = await getAllApplications();
|
|
||||||
}
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
function openApplication(id) {
|
function openApplication(id) {
|
||||||
|
if (!id) return;
|
||||||
router.push(`/administration/applications/${id}`)
|
router.push(`/administration/applications/${id}`)
|
||||||
openPanel.value = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function closeApplication() {
|
function closeApplication() {
|
||||||
router.push('/administration/applications')
|
router.push('/administration/applications')
|
||||||
openPanel.value = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
watch(() => route.params.id, (newId) => {
|
watch(() => route.params.id, (newId) => {
|
||||||
if (newId === undefined) {
|
if (newId === undefined) {
|
||||||
openPanel.value = false;
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const openPanel = ref(false);
|
// const openPanel = ref(false);
|
||||||
|
const openPanel = computed(() => route.params.id !== undefined)
|
||||||
|
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
appList.value = await getAllApplications();
|
appList.value = await getAllApplications();
|
||||||
@@ -102,7 +92,7 @@ onMounted(async () => {
|
|||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead>User</TableHead>
|
<TableHead>User</TableHead>
|
||||||
<TableHead>Date Submitted</TableHead>
|
<TableHead class="text-right">Date Submitted</TableHead>
|
||||||
<TableHead class="text-right">Status</TableHead>
|
<TableHead class="text-right">Status</TableHead>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
@@ -117,20 +107,10 @@ onMounted(async () => {
|
|||||||
<TableCell class="font-medium">
|
<TableCell class="font-medium">
|
||||||
<MemberCard :memberId="app.member_id"></MemberCard>
|
<MemberCard :memberId="app.member_id"></MemberCard>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell :title="formatExact(app.submitted_at)">
|
<TableCell class="text-right" :title="formatExact(app.submitted_at)">
|
||||||
{{ formatAgo(app.submitted_at) }}
|
{{ formatAgo(app.submitted_at) }}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|
||||||
<TableCell v-if="app.app_status === ApplicationStatus.Pending"
|
|
||||||
class="inline-flex items-end gap-2">
|
|
||||||
<Button variant="success" @click.stop="handleApprove(app.id)">
|
|
||||||
<CheckIcon />
|
|
||||||
</Button>
|
|
||||||
<Button variant="destructive" @click.stop="handleDeny(app.id)">
|
|
||||||
<XIcon />
|
|
||||||
</Button>
|
|
||||||
</TableCell>
|
|
||||||
|
|
||||||
<TableCell class="text-right font-semibold" :class="[
|
<TableCell class="text-right font-semibold" :class="[
|
||||||
app.app_status === ApplicationStatus.Pending && 'text-yellow-500',
|
app.app_status === ApplicationStatus.Pending && 'text-yellow-500',
|
||||||
app.app_status === ApplicationStatus.Accepted && 'text-green-500',
|
app.app_status === ApplicationStatus.Accepted && 'text-green-500',
|
||||||
|
|||||||
Reference in New Issue
Block a user