feat(survey): show job picker when navigating to /survey with no id
This commit is contained in:
parent
80999b9e7b
commit
3bfce5e6ef
1 changed files with 118 additions and 12 deletions
|
|
@ -13,11 +13,7 @@ const VALID_STAGES = ['survey', 'phone_screen', 'interviewing', 'offer']
|
||||||
|
|
||||||
const rawId = route.params.id
|
const rawId = route.params.id
|
||||||
const jobId = rawId ? parseInt(String(rawId), 10) : NaN
|
const jobId = rawId ? parseInt(String(rawId), 10) : NaN
|
||||||
|
const pickerMode = !rawId || isNaN(jobId)
|
||||||
// Redirect if no valid id
|
|
||||||
if (!jobId || isNaN(jobId)) {
|
|
||||||
router.replace('/interviews')
|
|
||||||
}
|
|
||||||
|
|
||||||
// UI state
|
// UI state
|
||||||
let saveSuccessTimer: ReturnType<typeof setTimeout> | null = null
|
let saveSuccessTimer: ReturnType<typeof setTimeout> | null = null
|
||||||
|
|
@ -35,11 +31,21 @@ const job = computed(() =>
|
||||||
interviewsStore.jobs.find(j => j.id === jobId) ?? null
|
interviewsStore.jobs.find(j => j.id === jobId) ?? null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Jobs eligible for survey (used in picker mode)
|
||||||
|
const pickerJobs = computed(() =>
|
||||||
|
interviewsStore.jobs.filter(j => VALID_STAGES.includes(j.status))
|
||||||
|
)
|
||||||
|
|
||||||
|
const stageLabel: Record<string, string> = {
|
||||||
|
survey: 'Survey', phone_screen: 'Phone Screen',
|
||||||
|
interviewing: 'Interviewing', offer: 'Offer',
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
if (!jobId || isNaN(jobId)) return
|
|
||||||
if (interviewsStore.jobs.length === 0) {
|
if (interviewsStore.jobs.length === 0) {
|
||||||
await interviewsStore.fetchAll()
|
await interviewsStore.fetchAll()
|
||||||
}
|
}
|
||||||
|
if (pickerMode) return
|
||||||
if (!job.value || !VALID_STAGES.includes(job.value.status)) {
|
if (!job.value || !VALID_STAGES.includes(job.value.status)) {
|
||||||
router.replace('/interviews')
|
router.replace('/interviews')
|
||||||
return
|
return
|
||||||
|
|
@ -126,12 +132,6 @@ async function saveToJob() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stage label helper
|
|
||||||
const stageLabel: Record<string, string> = {
|
|
||||||
survey: 'Survey', phone_screen: 'Phone Screen',
|
|
||||||
interviewing: 'Interviewing', offer: 'Offer',
|
|
||||||
}
|
|
||||||
|
|
||||||
// History accordion
|
// History accordion
|
||||||
const historyOpen = ref(false)
|
const historyOpen = ref(false)
|
||||||
function formatDate(iso: string | null): string {
|
function formatDate(iso: string | null): string {
|
||||||
|
|
@ -149,6 +149,32 @@ function toggleHistoryEntry(id: number) {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="survey-layout">
|
<div class="survey-layout">
|
||||||
|
|
||||||
|
<!-- ── Job picker (no id in route) ── -->
|
||||||
|
<div v-if="pickerMode" class="survey-content picker-mode">
|
||||||
|
<h2 class="picker-heading">Survey Assistant</h2>
|
||||||
|
<p class="picker-sub">Select a job to open the survey assistant.</p>
|
||||||
|
<div v-if="pickerJobs.length === 0" class="picker-empty">
|
||||||
|
No jobs in an active interview stage. Move a job to Survey, Phone Screen, Interviewing, or Offer first.
|
||||||
|
</div>
|
||||||
|
<ul v-else class="picker-list" role="list">
|
||||||
|
<li
|
||||||
|
v-for="j in pickerJobs"
|
||||||
|
:key="j.id"
|
||||||
|
class="picker-item"
|
||||||
|
@click="router.push('/survey/' + j.id)"
|
||||||
|
>
|
||||||
|
<div class="picker-item__main">
|
||||||
|
<span class="picker-item__company">{{ j.company }}</span>
|
||||||
|
<span class="picker-item__title">{{ j.title }}</span>
|
||||||
|
</div>
|
||||||
|
<span class="stage-badge">{{ stageLabel[j.status] ?? j.status }}</span>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- ── Survey assistant (id present) ── -->
|
||||||
|
<template v-else>
|
||||||
<!-- Sticky context bar -->
|
<!-- Sticky context bar -->
|
||||||
<div class="context-bar" v-if="job">
|
<div class="context-bar" v-if="job">
|
||||||
<span class="context-company">{{ job.company }}</span>
|
<span class="context-company">{{ job.company }}</span>
|
||||||
|
|
@ -305,6 +331,8 @@ function toggleHistoryEntry(id: number) {
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
|
</template><!-- end v-else (id present) -->
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -725,4 +753,82 @@ function toggleHistoryEntry(id: number) {
|
||||||
@keyframes spin {
|
@keyframes spin {
|
||||||
to { transform: rotate(360deg); }
|
to { transform: rotate(360deg); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Picker mode ── */
|
||||||
|
.picker-mode {
|
||||||
|
padding-top: var(--space-8, 2rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker-heading {
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--color-text, #1a202c);
|
||||||
|
margin: 0 0 var(--space-1) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker-sub {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: var(--color-text-muted, #718096);
|
||||||
|
margin: 0 0 var(--space-4) 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker-empty {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: var(--color-text-muted, #718096);
|
||||||
|
padding: var(--space-4);
|
||||||
|
border: 1px dashed var(--color-border, #e2e8f0);
|
||||||
|
border-radius: var(--radius-md, 8px);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker-list {
|
||||||
|
list-style: none;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: var(--space-2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: var(--space-3);
|
||||||
|
padding: var(--space-3) var(--space-4);
|
||||||
|
background: var(--color-surface, #fff);
|
||||||
|
border: 1px solid var(--color-border, #e2e8f0);
|
||||||
|
border-radius: var(--radius-md, 8px);
|
||||||
|
cursor: pointer;
|
||||||
|
transition: border-color 0.15s, background 0.15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker-item:hover {
|
||||||
|
border-color: var(--color-accent, #3182ce);
|
||||||
|
background: var(--color-accent-subtle, #ebf4ff);
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker-item__main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker-item__company {
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--color-text, #1a202c);
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker-item__title {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: var(--color-text-muted, #718096);
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue