diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 30edec26..22e9ec7d 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -12,14 +12,14 @@
"@pinia/colada": "^0.17.1",
"@tailwindcss/vite": "^4.1.11",
"@vee-validate/zod": "^4.15.1",
- "@vueuse/core": "^13.6.0",
+ "@vueuse/core": "^13.9.0",
"@vueuse/integrations": "^13.6.0",
"axios": "^1.11.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-vue-next": "^0.536.0",
"pinia": "^3.0.3",
- "reka-ui": "^2.7.0",
+ "reka-ui": "^2.8.0",
"tailwind-merge": "^3.3.1",
"tailwindcss": "^4.1.11",
"tw-animate-css": "^1.3.6",
@@ -2327,14 +2327,14 @@
}
},
"node_modules/@vueuse/core": {
- "version": "13.6.0",
- "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-13.6.0.tgz",
- "integrity": "sha512-DJbD5fV86muVmBgS9QQPddVX7d9hWYswzlf4bIyUD2dj8GC46R1uNClZhVAmsdVts4xb2jwp1PbpuiA50Qee1A==",
+ "version": "13.9.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-13.9.0.tgz",
+ "integrity": "sha512-ts3regBQyURfCE2BcytLqzm8+MmLlo5Ln/KLoxDVcsZ2gzIwVNnQpQOL/UKV8alUqjSZOlpFZcRNsLRqj+OzyA==",
"license": "MIT",
"dependencies": {
"@types/web-bluetooth": "^0.0.21",
- "@vueuse/metadata": "13.6.0",
- "@vueuse/shared": "13.6.0"
+ "@vueuse/metadata": "13.9.0",
+ "@vueuse/shared": "13.9.0"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
@@ -2343,6 +2343,18 @@
"vue": "^3.5.0"
}
},
+ "node_modules/@vueuse/core/node_modules/@vueuse/shared": {
+ "version": "13.9.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-13.9.0.tgz",
+ "integrity": "sha512-e89uuTLMh0U5cZ9iDpEI2senqPGfbPRTHM/0AaQkcxnpqjkZqDYP8rpfm7edOz8s+pOCOROEy1PIveSW8+fL5g==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "vue": "^3.5.0"
+ }
+ },
"node_modules/@vueuse/integrations": {
"version": "13.6.0",
"resolved": "https://registry.npmjs.org/@vueuse/integrations/-/integrations-13.6.0.tgz",
@@ -2409,7 +2421,24 @@
}
}
},
- "node_modules/@vueuse/metadata": {
+ "node_modules/@vueuse/integrations/node_modules/@vueuse/core": {
+ "version": "13.6.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-13.6.0.tgz",
+ "integrity": "sha512-DJbD5fV86muVmBgS9QQPddVX7d9hWYswzlf4bIyUD2dj8GC46R1uNClZhVAmsdVts4xb2jwp1PbpuiA50Qee1A==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/web-bluetooth": "^0.0.21",
+ "@vueuse/metadata": "13.6.0",
+ "@vueuse/shared": "13.6.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "vue": "^3.5.0"
+ }
+ },
+ "node_modules/@vueuse/integrations/node_modules/@vueuse/metadata": {
"version": "13.6.0",
"resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-13.6.0.tgz",
"integrity": "sha512-rnIH7JvU7NjrpexTsl2Iwv0V0yAx9cw7+clymjKuLSXG0QMcLD0LDgdNmXic+qL0SGvgSVPEpM9IDO/wqo1vkQ==",
@@ -2418,6 +2447,15 @@
"url": "https://github.com/sponsors/antfu"
}
},
+ "node_modules/@vueuse/metadata": {
+ "version": "13.9.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-13.9.0.tgz",
+ "integrity": "sha512-1AFRvuiGphfF7yWixZa0KwjYH8ulyjDCC0aFgrGRz8+P4kvDFSdXLVfTk5xAN9wEuD1J6z4/myMoYbnHoX07zg==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/antfu"
+ }
+ },
"node_modules/@vueuse/shared": {
"version": "13.6.0",
"resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-13.6.0.tgz",
@@ -5313,9 +5351,9 @@
"license": "MIT"
},
"node_modules/reka-ui": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/reka-ui/-/reka-ui-2.7.0.tgz",
- "integrity": "sha512-m+XmxQN2xtFzBP3OAdIafKq7C8OETo2fqfxcIIxYmNN2Ch3r5oAf6yEYCIJg5tL/yJU2mHqF70dCCekUkrAnXA==",
+ "version": "2.8.0",
+ "resolved": "https://registry.npmjs.org/reka-ui/-/reka-ui-2.8.0.tgz",
+ "integrity": "sha512-N4JOyIrmDE7w2i06WytqcV2QICubtS2PsK5Uo8FIMAgmO13KhUAgAByP26cXjjm2oF/w7rTyRs8YaqtvaBT+SA==",
"license": "MIT",
"dependencies": {
"@floating-ui/dom": "^1.6.13",
@@ -5323,8 +5361,8 @@
"@internationalized/date": "^3.5.0",
"@internationalized/number": "^3.5.0",
"@tanstack/vue-virtual": "^3.12.0",
- "@vueuse/core": "^12.5.0",
- "@vueuse/shared": "^12.5.0",
+ "@vueuse/core": "^14.1.0",
+ "@vueuse/shared": "^14.1.0",
"aria-hidden": "^1.2.4",
"defu": "^6.1.4",
"ohash": "^2.0.11"
@@ -5334,39 +5372,41 @@
}
},
"node_modules/reka-ui/node_modules/@vueuse/core": {
- "version": "12.8.2",
- "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-12.8.2.tgz",
- "integrity": "sha512-HbvCmZdzAu3VGi/pWYm5Ut+Kd9mn1ZHnn4L5G8kOQTPs/IwIAmJoBrmYk2ckLArgMXZj0AW3n5CAejLUO+PhdQ==",
+ "version": "14.2.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-14.2.0.tgz",
+ "integrity": "sha512-tpjzVl7KCQNVd/qcaCE9XbejL38V6KJAEq/tVXj7mDPtl6JtzmUdnXelSS+ULRkkrDgzYVK7EerQJvd2jR794Q==",
"license": "MIT",
"dependencies": {
"@types/web-bluetooth": "^0.0.21",
- "@vueuse/metadata": "12.8.2",
- "@vueuse/shared": "12.8.2",
- "vue": "^3.5.13"
+ "@vueuse/metadata": "14.2.0",
+ "@vueuse/shared": "14.2.0"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "vue": "^3.5.0"
}
},
"node_modules/reka-ui/node_modules/@vueuse/metadata": {
- "version": "12.8.2",
- "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-12.8.2.tgz",
- "integrity": "sha512-rAyLGEuoBJ/Il5AmFHiziCPdQzRt88VxR+Y/A/QhJ1EWtWqPBBAxTAFaSkviwEuOEZNtW8pvkPgoCZQ+HxqW1A==",
+ "version": "14.2.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-14.2.0.tgz",
+ "integrity": "sha512-i3axTGjU8b13FtyR4Keeama+43iD+BwX9C2TmzBVKqjSHArF03hjkp2SBZ1m72Jk2UtrX0aYCugBq2R1fhkuAQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/reka-ui/node_modules/@vueuse/shared": {
- "version": "12.8.2",
- "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-12.8.2.tgz",
- "integrity": "sha512-dznP38YzxZoNloI0qpEfpkms8knDtaoQ6Y/sfS0L7Yki4zh40LFHEhur0odJC6xTHG5dxWVPiUWBXn+wCG2s5w==",
+ "version": "14.2.0",
+ "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-14.2.0.tgz",
+ "integrity": "sha512-Z0bmluZTlAXgUcJ4uAFaML16JcD8V0QG00Db3quR642I99JXIDRa2MI2LGxiLVhcBjVnL1jOzIvT5TT2lqJlkA==",
"license": "MIT",
- "dependencies": {
- "vue": "^3.5.13"
- },
"funding": {
"url": "https://github.com/sponsors/antfu"
+ },
+ "peerDependencies": {
+ "vue": "^3.5.0"
}
},
"node_modules/require-directory": {
diff --git a/frontend/package.json b/frontend/package.json
index 181f139b..85bbe55d 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -21,14 +21,14 @@
"@pinia/colada": "^0.17.1",
"@tailwindcss/vite": "^4.1.11",
"@vee-validate/zod": "^4.15.1",
- "@vueuse/core": "^13.6.0",
+ "@vueuse/core": "^13.9.0",
"@vueuse/integrations": "^13.6.0",
"axios": "^1.11.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"lucide-vue-next": "^0.536.0",
"pinia": "^3.0.3",
- "reka-ui": "^2.7.0",
+ "reka-ui": "^2.8.0",
"tailwind-merge": "^3.3.1",
"tailwindcss": "^4.1.11",
"tw-animate-css": "^1.3.6",
diff --git a/frontend/src/components/ParticipationChip.vue b/frontend/src/components/ParticipationChip.vue
deleted file mode 100644
index e9a7684e..00000000
--- a/frontend/src/components/ParticipationChip.vue
+++ /dev/null
@@ -1,190 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/frontend/src/components/ParticipationFilters.vue b/frontend/src/components/ParticipationFilters.vue
new file mode 100644
index 00000000..a7ec3bbb
--- /dev/null
+++ b/frontend/src/components/ParticipationFilters.vue
@@ -0,0 +1,225 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/components/ParticipationStatusBadge.vue b/frontend/src/components/ParticipationStatusBadge.vue
new file mode 100644
index 00000000..516fc300
--- /dev/null
+++ b/frontend/src/components/ParticipationStatusBadge.vue
@@ -0,0 +1,104 @@
+
+
+
+
+ {{ humanReadableParticipationStatus[currentStatus] }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/components/cards/CompanyCard.vue b/frontend/src/components/cards/CompanyCard.vue
index 93de3c2e..0aa76192 100644
--- a/frontend/src/components/cards/CompanyCard.vue
+++ b/frontend/src/components/cards/CompanyCard.vue
@@ -73,6 +73,16 @@
{{ company.name }}
+
+
+ {{ packageData.name }}
+
Partner
@@ -138,6 +148,7 @@ import type {
} from "@/dto/companies";
import { useCompanyInfoMutation } from "@/mutations/companies";
import { useCompanyImageUploadMutation } from "@/mutations/companies";
+import { usePackageQuery } from "@/mutations/packages";
import { deleteCompany } from "@/api/companies";
import { useAuthStore } from "@/stores/auth";
import { useQueryCache } from "@pinia/colada";
@@ -154,6 +165,7 @@ import CompanyInfoForm from "../companies/CompanyInfoForm.vue";
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
import { TrashIcon } from "lucide-vue-next";
import ConfirmDelete from "@/components/ConfirmDelete.vue";
+import ParticipationStatusBadge from "@/components/ParticipationStatusBadge.vue";
const props = defineProps<{
company: CompanyWithParticipation;
@@ -164,6 +176,10 @@ const emit = defineEmits<{
deleted: [];
}>();
+// Fetch package data if the company has a package
+const packageId = computed(() => props.company.participation?.package);
+const { data: packageData } = usePackageQuery(packageId);
+
const isDescriptionExpanded = ref(false);
const isEditing = ref(false);
const isDeleteConfirmOpen = ref(false);
diff --git a/frontend/src/components/cards/CompanyWorkflowCard.vue b/frontend/src/components/cards/CompanyWorkflowCard.vue
index bc932a52..199f4cf9 100644
--- a/frontend/src/components/cards/CompanyWorkflowCard.vue
+++ b/frontend/src/components/cards/CompanyWorkflowCard.vue
@@ -4,28 +4,97 @@
:image="company.imgs?.internal || company.imgs?.public"
:title="company.name"
:current-status="company.participation?.status"
- :badge="company.participation?.partner ? 'Partner' : ''"
+ :badges="badges"
+ :is-loading="isUpdatingStatus"
:to="{ name: 'company', params: { companyId: company.id } }"
@status-change="updateCompanyStatus(company, $event)"
/>
diff --git a/frontend/src/components/cards/SpeakerCard.vue b/frontend/src/components/cards/SpeakerCard.vue
index 6c801c2d..74bb20b6 100644
--- a/frontend/src/components/cards/SpeakerCard.vue
+++ b/frontend/src/components/cards/SpeakerCard.vue
@@ -81,6 +81,13 @@
{{ speaker.title }}
+
{{ speaker.companyName }}
@@ -141,6 +148,7 @@ import SpeakerInfoForm from "../speakers/SpeakerInfoForm.vue";
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
import { TrashIcon } from "lucide-vue-next";
import ConfirmDelete from "@/components/ConfirmDelete.vue";
+import ParticipationStatusBadge from "@/components/ParticipationStatusBadge.vue";
const props = defineProps<{
speaker: SpeakerWithParticipation;
diff --git a/frontend/src/components/cards/SpeakerWorkflowCard.vue b/frontend/src/components/cards/SpeakerWorkflowCard.vue
index 01f2d541..9fc4c499 100644
--- a/frontend/src/components/cards/SpeakerWorkflowCard.vue
+++ b/frontend/src/components/cards/SpeakerWorkflowCard.vue
@@ -6,12 +6,14 @@
"
:title="speaker.name"
:current-status="speaker.participation?.status"
+ :is-loading="isUpdatingStatus"
:to="{ name: 'speaker', params: { speakerId: speaker.id } }"
@status-change="updateSpeakerStatus(speaker, $event)"
/>
diff --git a/frontend/src/components/cards/WorkflowCard.vue b/frontend/src/components/cards/WorkflowCard.vue
index 628e1ed4..f8da7254 100644
--- a/frontend/src/components/cards/WorkflowCard.vue
+++ b/frontend/src/components/cards/WorkflowCard.vue
@@ -8,24 +8,37 @@ import {
SelectTrigger,
SelectValue,
} from "../ui/select";
-import { computed, watch, ref } from "vue";
+import { computed, watch, ref, type Component } from "vue";
import {
humanReadableParticipationStatus,
participationNextValues,
participationStatusColor,
type ParticipationStatus,
} from "@/dto";
-import { Badge } from "../ui/badge";
import type { RouteLocationRaw } from "vue-router";
import ConfettiExplosion from "vue-confetti-explosion";
import confettiAudio from "@/assets/audio/confetti.mp3";
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipProvider,
+ TooltipTrigger,
+} from "../ui/tooltip";
+import { Loader2 } from "lucide-vue-next";
+
+export interface WorkflowBadge {
+ icon: Component;
+ label: string;
+ color?: string;
+ bgColor?: string;
+}
const props = defineProps<{
title: string;
currentStatus?: ParticipationStatus;
image?: string;
- loading?: boolean;
- badge?: string;
+ isLoading?: boolean;
+ badges?: WorkflowBadge[];
to?: RouteLocationRaw;
}>();
@@ -102,13 +115,18 @@ watch(
{{ humanReadableParticipationStatus[selectedStatus] }}
-