Files
pc_builder/inertia/pages/widgets/ComponentEditor.vue
T
2026-06-28 10:41:51 +02:00

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>