Fixed a whole lotta broken stuff by changing state from a string to a number

This commit is contained in:
2026-02-07 13:25:15 -05:00
parent d321c83f49
commit 1101f0eb59
17 changed files with 435 additions and 260 deletions

View File

@@ -12,6 +12,7 @@ import { useCalendarEvents } from '@/composables/useCalendarEvents'
import { useCalendarNavigation } from '@/composables/useCalendarNavigation'
import { useUserStore } from '@/stores/user'
import { CalendarOptions } from '@fullcalendar/core'
import { MemberState } from '@shared/types/member'
const monthLabels = [
'January', 'February', 'March', 'April', 'May', 'June',
@@ -50,7 +51,7 @@ const dialogRef = ref<any>(null)
// NEW: handle day/time slot clicks to start creating an event
function onDateClick(arg: { dateStr: string }) {
if (!userStore.isLoggedIn) return;
if (userStore.state !== 'member') return;
if (userStore.state !== MemberState.Member) return;
dialogRef.value?.openDialog(arg.dateStr);
}
@@ -198,7 +199,7 @@ onMounted(() => {
@click="goToday">
Today
</button>
<button v-if="userStore.isLoggedIn && userStore.state === 'member'"
<button v-if="userStore.isLoggedIn && userStore.state === MemberState.Member"
class="cursor-pointer ml-1 inline-flex items-center gap-1.5 rounded-md bg-primary px-3 py-1.5 text-sm text-primary-foreground hover:opacity-90"
@click="onCreateEvent">
<Plus class="h-4 w-4" />

View File

@@ -2,6 +2,7 @@
import { getWelcomeMessage } from '@/api/docs';
import { Button } from '@/components/ui/button'
import { useUserStore } from '@/stores/user'
import { MemberState } from '@shared/types/member';
import { onMounted, ref } from 'vue';
import { useRouter } from 'vue-router'
@@ -14,7 +15,7 @@ function goToApplication() {
}
onMounted(async () => {
if (user.state == 'member') {
if (user.state == MemberState.Member) {
let policy = await getWelcomeMessage() as any;
welcomeRef.value.innerHTML = policy;
}
@@ -25,7 +26,7 @@ const welcomeRef = ref<HTMLElement>(null);
<template>
<div>
<div v-if="user.state == 'member'" class="mt-10">
<div v-if="user.state == MemberState.Member" class="mt-10">
<div ref="welcomeRef" class="bookstack-container">
<!-- bookstack -->
</div>

View File

@@ -1,90 +1,93 @@
<script setup lang="ts">
import ApplicationForm from '@/components/application/ApplicationForm.vue';
import Button from '@/components/ui/button/Button.vue';
import {
Stepper,
StepperDescription,
StepperIndicator,
StepperItem,
StepperSeparator,
StepperTitle,
StepperTrigger,
} from '@/components/ui/stepper'
import { useUserStore } from '@/stores/user';
import { Check, Circle, Dot, Users, X } from 'lucide-vue-next'
import { computed, ref } from 'vue';
import Application from './Application.vue';
import { restartApplication } from '@/api/application';
import ApplicationForm from '@/components/application/ApplicationForm.vue';
import Button from '@/components/ui/button/Button.vue';
import {
Stepper,
StepperDescription,
StepperIndicator,
StepperItem,
StepperSeparator,
StepperTitle,
StepperTrigger,
} from '@/components/ui/stepper'
import { useUserStore } from '@/stores/user';
import { Check, Circle, Dot, Users, X } from 'lucide-vue-next'
import { computed, ref } from 'vue';
import Application from './Application.vue';
import { restartApplication } from '@/api/application';
import { MemberState } from '@shared/types/member';
function goToLogin() {
const redirectUrl = encodeURIComponent(window.location.origin + '/join')
//@ts-ignore
const addr = import.meta.env.VITE_APIHOST;
window.location.href = `${addr}/login?redirect=${redirectUrl}`;
}
let userStore = useUserStore();
const steps = computed(() => {
const isDenied = userStore.state === 'denied'
return [
{
step: 1,
title: 'Create account',
description: 'Begin by setting up your account',
},
{
step: 2,
title: 'Submit application',
description: 'Provide a few details about yourself',
},
{
step: 3,
title: 'Application review',
description: 'Our team will review your submission',
},
{
step: 4,
title: isDenied ? 'Application denied' : 'Acceptance',
description: isDenied
? 'Your application was not approved'
: 'Get started with the 17th Rangers',
},
]
})
const currentStep = computed<number>(() => {
if (!userStore.isLoggedIn)
return 1;
switch (userStore.state) {
case "guest":
return 2;
break;
case "applicant":
return 3;
break;
case "member":
return 5;
break;
case "denied":
return 5;
break;
case "retired":
return 5;
break;
function goToLogin() {
const redirectUrl = encodeURIComponent(window.location.origin + '/join')
//@ts-ignore
const addr = import.meta.env.VITE_APIHOST;
window.location.href = `${addr}/login?redirect=${redirectUrl}`;
}
})
const finalPanel = ref<'app' | 'message'>('message');
let userStore = useUserStore();
const reloadKey = ref(0);
const steps = computed(() => {
const isDenied = userStore.state === MemberState.Denied
async function restartApp() {
await restartApplication();
await userStore.loadUser();
reloadKey.value++;
}
return [
{
step: 1,
title: 'Create account',
description: 'Begin by setting up your account',
},
{
step: 2,
title: 'Submit application',
description: 'Provide a few details about yourself',
},
{
step: 3,
title: 'Application review',
description: 'Our team will review your submission',
},
{
step: 4,
title: isDenied ? 'Application denied' : 'Acceptance',
description: isDenied
? 'Your application was not approved'
: 'Get started with the 17th Rangers',
},
]
})
const currentStep = computed<number>(() => {
if (!userStore.isLoggedIn)
return 1;
switch (userStore.state) {
case MemberState.Guest:
return 2;
break;
case MemberState.Applicant:
return 3;
break;
case MemberState.Member:
return 5;
break;
case MemberState.Denied:
return 5;
break;
case MemberState.Retired:
return 5;
case MemberState.Discharged:
return 5;
break;
}
})
const finalPanel = ref<'app' | 'message'>('message');
const reloadKey = ref(0);
async function restartApp() {
await restartApplication();
await userStore.loadUser();
reloadKey.value++;
}
</script>
<template>
@@ -104,7 +107,8 @@ async function restartApp() {
size="icon" class="z-10 rounded-full shrink-0"
:class="[state === 'active' && 'ring-2 ring-ring ring-offset-2 ring-offset-background']">
<template v-if="state === 'completed'">
<X v-if="step.step === 4 && userStore.state === 'denied'" class="size-5" />
<X v-if="step.step === 4 && userStore.state === MemberState.Denied"
class="size-5" />
<Check v-else class="size-5" />
</template>
<Circle v-if="state === 'active'" />
@@ -160,7 +164,7 @@ async function restartApp() {
</div>
<div v-if="finalPanel === 'message'">
<!-- Accepted message -->
<div v-if="userStore.state === 'member'">
<div v-if="userStore.state === MemberState.Member">
<h1 class="text-3xl sm:text-4xl font-bold mb-4 text-left">
Welcome to the 17th Ranger Battalion
</h1>
@@ -232,7 +236,7 @@ async function restartApp() {
</div>
</div>
<!-- Denied message -->
<div v-else-if="userStore.state === 'denied'">
<div v-else-if="userStore.state === MemberState.Denied">
<div class="w-full max-w-2xl flex flex-col gap-8">
<h1 class="text-3xl sm:text-4xl font-bold text-left">
Application Not Approved
@@ -263,7 +267,8 @@ async function restartApp() {
<Button class="w-min" @click="restartApp">New Application</Button>
</div>
</div>
<div v-else-if="userStore.state === 'retired'">
<div
v-else-if="userStore.state === MemberState.Discharged || userStore.state === MemberState.Retired">
<div class="w-full max-w-2xl flex flex-col gap-8">
<h1 class="text-3xl sm:text-4xl font-bold text-left">
You have retired from the 17th Ranger Battalion

View File

@@ -135,11 +135,15 @@ onMounted(() => {
const isDischargeOpen = ref(false)
const targetMember = ref(null)
function openDischargeModal(member) {
function openDischargeModal(member: Member) {
targetMember.value = member
isDischargeOpen.value = true
}
function suspendMember(member: Member) {
}
function handleDischargeSuccess(data) {
fetchMembers();
}
@@ -186,8 +190,8 @@ function handleDischargeSuccess(data) {
</Select>
<div v-if="filters.status !== 'all' || filters.unitId !== 'all'"
class="h-4 w-[1px] bg-border mx-1" />
<Button v-if="filters.status !== MemberState.Member || filters.unitId !== 'all'" variant="ghost" size="sm"
class="h-8 px-2 text-xs text-muted-foreground"
<Button v-if="filters.status !== MemberState.Member || filters.unitId !== 'all'" variant="ghost"
size="sm" class="h-8 px-2 text-xs text-muted-foreground"
@click="filters.status = MemberState.Member; filters.unitId = 'all'">
Clear Filters
</Button>
@@ -250,6 +254,10 @@ function handleDischargeSuccess(data) {
class="text-destructive focus:bg-destructive focus:text-destructive-foreground font-medium">
Discharge Member
</DropdownMenuItem>
<DropdownMenuItem @click="suspendMember(member)"
class="text-destructive focus:bg-destructive focus:text-destructive-foreground font-medium">
Suspend Member
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</TableCell>