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 {
|
||||
const app = await getApplicationByID(appID);
|
||||
const result = await approveApplication(appID);
|
||||
|
||||
//guard against failures
|
||||
if (result.affectedRows != 1) {
|
||||
throw new Error("Something went wrong approving the application");
|
||||
}
|
||||
await approveApplication(appID, approved_by);
|
||||
|
||||
//update user profile
|
||||
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])
|
||||
// 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) {
|
||||
console.error('Approve failed:', err);
|
||||
@@ -178,12 +170,13 @@ router.post('/approve/:id', [requireLogin, requireRole("Recruiter")], async (req
|
||||
});
|
||||
|
||||
// POST /application/deny/:id
|
||||
router.post('/deny/:id', [requireLogin, requireRole("Recruiter")], async (req, res) => {
|
||||
const appID = req.params.id;
|
||||
router.post('/deny/:id', [requireLogin, requireRole("Recruiter")], async (req: Request, res: Response) => {
|
||||
const appID = Number(req.params.id);
|
||||
const approver = Number(req.user.id);
|
||||
|
||||
try {
|
||||
const app = await getApplicationByID(appID);
|
||||
await denyApplication(appID);
|
||||
await denyApplication(appID, approver);
|
||||
await setUserState(app.member_id, MemberState.Denied);
|
||||
res.sendStatus(200);
|
||||
} catch (err) {
|
||||
|
||||
@@ -31,7 +31,7 @@ export async function getApplicationByID(appID: number): Promise<ApplicationRow>
|
||||
return app[0];
|
||||
}
|
||||
|
||||
export async function getApplicationList(): Promise<ApplicationListRow[]> {
|
||||
export async function getApplicationList(page: number = 1, pageSize: number = 25): Promise<ApplicationListRow[]> {
|
||||
const sql = `SELECT
|
||||
member.name AS member_name,
|
||||
app.id,
|
||||
@@ -40,9 +40,11 @@ export async function getApplicationList(): Promise<ApplicationListRow[]> {
|
||||
app.app_status
|
||||
FROM applications AS app
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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 = `
|
||||
UPDATE applications
|
||||
SET approved_at = NOW()
|
||||
SET approved_at = NOW(), approved_by = ?
|
||||
WHERE id = ?
|
||||
AND approved_at IS NULL
|
||||
AND denied_at IS NULL
|
||||
`;
|
||||
|
||||
const result = await pool.execute(sql, id);
|
||||
return result;
|
||||
const result = await pool.execute(sql, [approver, id]);
|
||||
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 = `
|
||||
UPDATE applications
|
||||
SET denied_at = NOW()
|
||||
SET denied_at = NOW(), approved_by = ?
|
||||
WHERE id = ?
|
||||
AND approved_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) {
|
||||
return
|
||||
} else {
|
||||
|
||||
@@ -94,16 +94,18 @@ export async function approveApplication(id: Number) {
|
||||
const res = await fetch(`${addr}/application/approve/${id}`, { method: 'POST', credentials: 'include' })
|
||||
|
||||
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) {
|
||||
const res = await fetch(`${addr}/application/deny/${id}`, { method: 'POST', credentials: 'include' })
|
||||
|
||||
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() {
|
||||
|
||||
@@ -174,7 +174,7 @@ watch(() => showCoC.value, async () => {
|
||||
<FormLabel>Have you ever served in the military?</FormLabel>
|
||||
<FormControl>
|
||||
<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>
|
||||
</div>
|
||||
</FormControl>
|
||||
|
||||
@@ -105,12 +105,21 @@ async function postApp(appData) {
|
||||
}
|
||||
|
||||
async function handleApprove(id) {
|
||||
console.log("hi");
|
||||
try {
|
||||
await approveApplication(id);
|
||||
loadData(await loadApplication(Number(route.params.id), true))
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleDeny(id) {
|
||||
try {
|
||||
await denyApplication(id);
|
||||
loadData(await loadApplication(Number(route.params.id), true))
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -164,7 +173,8 @@ async function handleDeny(id) {
|
||||
</ApplicationForm>
|
||||
<div v-if="!newApp" class="pb-15">
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
TableRow,
|
||||
} from '@/components/ui/table'
|
||||
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 { CheckIcon, XIcon } from 'lucide-vue-next';
|
||||
import Application from './Application.vue';
|
||||
@@ -52,36 +52,26 @@ function formatExact(iso) {
|
||||
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();
|
||||
function openApplication(id) {
|
||||
if (!id) return;
|
||||
router.push(`/administration/applications/${id}`)
|
||||
openPanel.value = true;
|
||||
}
|
||||
|
||||
function closeApplication() {
|
||||
router.push('/administration/applications')
|
||||
openPanel.value = false;
|
||||
}
|
||||
|
||||
const route = useRoute();
|
||||
|
||||
watch(() => route.params.id, (newId) => {
|
||||
if (newId === undefined) {
|
||||
openPanel.value = false;
|
||||
}
|
||||
})
|
||||
|
||||
const openPanel = ref(false);
|
||||
// const openPanel = ref(false);
|
||||
const openPanel = computed(() => route.params.id !== undefined)
|
||||
|
||||
|
||||
onMounted(async () => {
|
||||
appList.value = await getAllApplications();
|
||||
@@ -102,7 +92,7 @@ onMounted(async () => {
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>User</TableHead>
|
||||
<TableHead>Date Submitted</TableHead>
|
||||
<TableHead class="text-right">Date Submitted</TableHead>
|
||||
<TableHead class="text-right">Status</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
@@ -117,20 +107,10 @@ onMounted(async () => {
|
||||
<TableCell class="font-medium">
|
||||
<MemberCard :memberId="app.member_id"></MemberCard>
|
||||
</TableCell>
|
||||
<TableCell :title="formatExact(app.submitted_at)">
|
||||
<TableCell class="text-right" :title="formatExact(app.submitted_at)">
|
||||
{{ formatAgo(app.submitted_at) }}
|
||||
</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="[
|
||||
app.app_status === ApplicationStatus.Pending && 'text-yellow-500',
|
||||
app.app_status === ApplicationStatus.Accepted && 'text-green-500',
|
||||
|
||||
Reference in New Issue
Block a user