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 @@ + + + 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] }}
- - {{ humanReadableParticipationStatus[selectedStatus] }} + + {{ humanReadableParticipationStatus[selectedStatus] }} + + @@ -139,7 +160,27 @@ watch( {{ title }} - {{ badge }} +
+ + + +
+ +
+
+ +

{{ badge.label }}

+
+
+
+
diff --git a/frontend/src/components/companies/ContractDownload.vue b/frontend/src/components/companies/ContractDownload.vue index 65a502ee..e741e67d 100644 --- a/frontend/src/components/companies/ContractDownload.vue +++ b/frontend/src/components/companies/ContractDownload.vue @@ -1,8 +1,9 @@