Skip to content

Commit 96b7e0d

Browse files
committed
feat: tasks prototype
1 parent ce31ce2 commit 96b7e0d

File tree

2 files changed

+157
-0
lines changed

2 files changed

+157
-0
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<template>
2+
<StepperItem
3+
:step="stepNumber"
4+
class="flex gap-4 items-stretch"
5+
:completed="!isComplete"
6+
>
7+
<div class="flex flex-col items-center">
8+
<StepperIndicator class="shrink-0">
9+
<slot name="icon" />
10+
</StepperIndicator>
11+
<StepperSeparator
12+
v-if="!isLast"
13+
class="flex-1 w-0.5 min-h-4 my-1 !bg-muted"
14+
/>
15+
</div>
16+
<div class="flex-1" :class="{ 'pb-4': !isLast }">
17+
<Collapsible v-model:open="isOpen" class="w-full">
18+
<Card class="p-4">
19+
<div
20+
class="flex items-center justify-between cursor-pointer"
21+
@click="isOpen = !isOpen"
22+
>
23+
<h3 class="font-medium flex items-center gap-2">
24+
{{ title }}
25+
</h3>
26+
<div class="flex items-center gap-2">
27+
<div @click.stop>
28+
<slot name="header-actions" />
29+
</div>
30+
<Badge v-if="isComplete" variant="default"> Complete </Badge>
31+
<Badge v-else variant="secondary"> Pending </Badge>
32+
<ChevronDown
33+
class="h-4 w-4 transition-transform duration-200"
34+
:class="{ 'rotate-180': isOpen }"
35+
/>
36+
</div>
37+
</div>
38+
<CollapsibleContent class="mt-4">
39+
<slot />
40+
</CollapsibleContent>
41+
</Card>
42+
</Collapsible>
43+
</div>
44+
</StepperItem>
45+
</template>
46+
47+
<script setup lang="ts">
48+
import { ref } from "vue";
49+
import { Card } from "@/components/ui/card";
50+
import { Badge } from "@/components/ui/badge";
51+
import { Collapsible, CollapsibleContent } from "@/components/ui/collapsible";
52+
import {
53+
StepperItem,
54+
StepperIndicator,
55+
StepperSeparator,
56+
} from "@/components/ui/stepper";
57+
import { ChevronDown } from "lucide-vue-next";
58+
59+
interface Props {
60+
stepNumber: number;
61+
title: string;
62+
isComplete: boolean;
63+
isLast?: boolean;
64+
}
65+
66+
const props = withDefaults(defineProps<Props>(), {
67+
isLast: false,
68+
});
69+
70+
// Start collapsed if complete, open if incomplete
71+
const isOpen = ref(!props.isComplete);
72+
</script>
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<template>
2+
<div class="p-4 space-y-6">
3+
<h2 class="text-lg font-semibold">Company Tasks Timeline</h2>
4+
5+
<!-- Stepper Container -->
6+
<Stepper
7+
v-model="currentStep"
8+
orientation="vertical"
9+
:linear="false"
10+
class="flex flex-col"
11+
>
12+
<TaskConfirmation
13+
:company-id="companyWithParticipation.id"
14+
:participation="currentParticipation"
15+
@package-changed="onPackageChanged"
16+
/>
17+
18+
<TaskBillingLogos
19+
:billing-info="companyWithParticipation.billingInfo"
20+
:company-id="companyWithParticipation.id"
21+
/>
22+
23+
<TaskContract :company-id="companyWithParticipation.id" />
24+
25+
<TaskSessionTitles
26+
v-if="showSessionTitles"
27+
:package-items="packageItems"
28+
/>
29+
30+
<TaskCorlief
31+
:company-id="companyWithParticipation.id"
32+
:step-number="showSessionTitles ? 5 : 4"
33+
/>
34+
35+
<TaskLogistics
36+
:company-id="companyWithParticipation.id"
37+
:step-number="showSessionTitles ? 6 : 5"
38+
:is-last="true"
39+
/>
40+
</Stepper>
41+
</div>
42+
</template>
43+
44+
<script setup lang="ts">
45+
import { ref, computed } from "vue";
46+
import type { CompanyWithParticipation } from "@/dto/companies";
47+
import type { Item } from "@/dto/item";
48+
import { Stepper } from "@/components/ui/stepper";
49+
import TaskConfirmation from "../../../../components/tasks/TaskConfirmation.vue";
50+
import TaskBillingLogos from "../../../../components/tasks/TaskBillingLogos.vue";
51+
import TaskContract from "../../../../components/tasks/TaskContract.vue";
52+
import TaskSessionTitles from "../../../../components/tasks/TaskSessionTitles.vue";
53+
import TaskCorlief from "../../../../components/tasks/TaskCorlief.vue";
54+
import TaskLogistics from "../../../../components/tasks/TaskLogistics.vue";
55+
56+
interface Props {
57+
companyWithParticipation: CompanyWithParticipation;
58+
}
59+
60+
const props = defineProps<Props>();
61+
62+
// Get current participation
63+
const currentParticipation = computed(
64+
() => props.companyWithParticipation?.participation,
65+
);
66+
67+
// Package items for session titles
68+
const packageItems = ref<Item[]>([]);
69+
70+
const onPackageChanged = (_name: string, items: Item[]) => {
71+
packageItems.value = items;
72+
};
73+
74+
// Show session titles only if package has presentation or workshop items
75+
const showSessionTitles = computed(() => {
76+
return packageItems.value.some(
77+
(item) =>
78+
item.name?.toLowerCase() === "presentation" ||
79+
item.name?.toLowerCase() === "workshop",
80+
);
81+
});
82+
83+
// Set current step to 0 so the stepper doesn't auto-mark any steps as completed
84+
const currentStep = ref(0);
85+
</script>

0 commit comments

Comments
 (0)