157 lines
4.7 KiB
Vue
157 lines
4.7 KiB
Vue
<script setup lang="ts">
|
|
import { computed, defineEmits, defineProps, onMounted, ref, watch } from 'vue'
|
|
import { Component } from '~/pages/types/UITypes'
|
|
|
|
interface ComponentsByType {
|
|
type: string
|
|
components: Component[]
|
|
}
|
|
|
|
const props = defineProps<{
|
|
availableComponents: Component[]
|
|
selectedComponents: number[]
|
|
initialSelectedComponents?: Component[]
|
|
}>()
|
|
|
|
const emit = defineEmits(['update:components'])
|
|
|
|
const componentTypeOrder = [
|
|
'Processor',
|
|
'Motherboard',
|
|
'Graphic Card',
|
|
'Memory',
|
|
'HDD',
|
|
'SSD',
|
|
'Cooler',
|
|
'Power Supply',
|
|
'Case',
|
|
'WiFi-Card',
|
|
'Fan',
|
|
'Other',
|
|
]
|
|
|
|
// Fusionner les composants disponibles et initialement s├®lectionn├®s
|
|
const allComponents = computed(() => {
|
|
const mergedComponents = [...props.availableComponents]
|
|
if (props.initialSelectedComponents) {
|
|
props.initialSelectedComponents.forEach((component) => {
|
|
if (!mergedComponents.find((c) => c.id === component.id)) {
|
|
mergedComponents.push(component)
|
|
}
|
|
})
|
|
}
|
|
return mergedComponents
|
|
})
|
|
|
|
// Trier les composants par type
|
|
const componentsByType = computed(() => {
|
|
const groupedComponents: Record<string, Component[]> = {}
|
|
|
|
allComponents.value.forEach((component) => {
|
|
const type = component.type.name
|
|
if (!groupedComponents[type]) {
|
|
groupedComponents[type] = []
|
|
}
|
|
groupedComponents[type].push(component)
|
|
})
|
|
|
|
const sortedComponentsByType: ComponentsByType[] = componentTypeOrder.map((type) => ({
|
|
type,
|
|
components: groupedComponents[type] || [],
|
|
}))
|
|
|
|
return sortedComponentsByType.filter((group) => group.components.length > 0)
|
|
})
|
|
|
|
// Initialisation de selectedComponents
|
|
let selectedComponents = ref<number[]>(
|
|
props.initialSelectedComponents?.map((c) => c.id) || props.selectedComponents || []
|
|
)
|
|
// Synchroniser les props avec le composant
|
|
watch(
|
|
() => props.selectedComponents,
|
|
(newVal) => {
|
|
selectedComponents.value = newVal
|
|
}
|
|
)
|
|
|
|
onMounted(() => {
|
|
if (props.initialSelectedComponents) {
|
|
emit(
|
|
'update:components',
|
|
props.initialSelectedComponents.map((c) => c.id)
|
|
)
|
|
}
|
|
})
|
|
|
|
function updateComponents(event: Event, type: string) {
|
|
const selectedComponentId = Number((event.target as HTMLSelectElement).value)
|
|
const updatedComponents = [...selectedComponents.value]
|
|
|
|
const alreadyInListComponentIndex = updatedComponents.findIndex((id) => {
|
|
return selectedComponentId === id
|
|
})
|
|
|
|
if (alreadyInListComponentIndex !== -1) {
|
|
updatedComponents.splice(alreadyInListComponentIndex, 1)
|
|
} else {
|
|
const typeIndex = componentsByType.value.findIndex((item) => item.type === type)
|
|
const existingComponentIndex = updatedComponents.findIndex((id) => {
|
|
const component = componentsByType.value[typeIndex].components.find((c) => c.id === id)
|
|
return component && component.type.unique
|
|
})
|
|
if (existingComponentIndex !== -1) updatedComponents.splice(existingComponentIndex, 1)
|
|
|
|
if (selectedComponentId != 0) updatedComponents.push(Number(selectedComponentId))
|
|
}
|
|
|
|
selectedComponents.value = updatedComponents
|
|
emit('update:components', updatedComponents)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div v-for="{ type, components } in componentsByType" :key="type">
|
|
<label :for="`select-${type}`" class="block text-gray-700 text-sm font-bold mb-1 mt-2">
|
|
{{ type }}
|
|
</label>
|
|
<div v-if="components[0]?.type.unique">
|
|
<!-- Utilisation d'un select pour les composants uniques -->
|
|
<select
|
|
@change="updateComponents($event, type)"
|
|
:id="`select-${type}`"
|
|
class="w-full mt-2 border-gray-200 focus:border-indigo-600 focus:ring-indigo-500 px-3 py-2 focus:ring-1 border rounded text-gray-700 bg-white"
|
|
>
|
|
<option value="" selected>Select a component</option>
|
|
<option
|
|
v-for="component in components"
|
|
:key="component.id"
|
|
:value="component.id"
|
|
:selected="selectedComponents.includes(component.id)"
|
|
>
|
|
{{ component.name }}
|
|
</option>
|
|
</select>
|
|
</div>
|
|
<div v-else>
|
|
<!-- Utilisation de cases à cocher pour les composants non uniques avec grille responsive -->
|
|
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
|
|
<div v-for="component in components" :key="component.id" class="flex items-center mt-1">
|
|
<input
|
|
type="checkbox"
|
|
@click="updateComponents($event, type)"
|
|
:id="`checkbox-${component.id}`"
|
|
:value="component.id"
|
|
v-model="selectedComponents"
|
|
class="mr-2"
|
|
:checked="selectedComponents.includes(component.id)"
|
|
/>
|
|
<label :for="`checkbox-${component.id}`" class="text-sm text-gray-700">
|
|
{{ component.name }}
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|