---
globs: src/components/**/*.vue
---

# Component Patterns và Best Practices

## Component Structure
Mỗi component nên có structure rõ ràng:

```vue
<template>
  <!-- Template content -->
</template>

<script setup>
// Script content
</script>

<style scoped>
/* Component-specific styles */
</style>
```

## Props và Emits
```vue
<script setup>
// Props với validation
const props = defineProps({
  title: {
    type: String,
    required: true
  },
  items: {
    type: Array,
    default: () => []
  },
  isLoading: {
    type: Boolean,
    default: false
  }
})

// Emits với validation
const emit = defineEmits({
  update: (value) => typeof value === 'string',
  delete: (id) => typeof id === 'number',
  'item-click': (item) => typeof item === 'object'
})
</script>
```

## Reusable Components
Các component trong [components/](mdc:src/components/) nên được thiết kế để tái sử dụng:

### Form Components
```vue
<!-- components/forms/BaseInput.vue -->
<template>
  <div class="form-group">
    <label v-if="label" :for="id" class="form-label">
      {{ label }}
      <span v-if="required" class="text-danger">*</span>
    </label>
    <input
      :id="id"
      :type="type"
      :value="modelValue"
      :placeholder="placeholder"
      :required="required"
      :disabled="disabled"
      class="form-control"
      :class="{ 'is-invalid': error }"
      @input="$emit('update:modelValue', $event.target.value)"
    />
    <div v-if="error" class="invalid-feedback">
      {{ error }}
    </div>
  </div>
</template>

<script setup>
const props = defineProps({
  modelValue: [String, Number],
  type: {
    type: String,
    default: 'text'
  },
  label: String,
  placeholder: String,
  required: Boolean,
  disabled: Boolean,
  error: String
})

const emit = defineEmits(['update:modelValue'])

const id = computed(() => `input-${Math.random().toString(36).substr(2, 9)}`)
</script>
```

### List Components
```vue
<!-- components/lists/DataTable.vue -->
<template>
  <div class="data-table">
    <div v-if="loading" class="text-center p-4">
      <Loader />
    </div>
    
    <div v-else-if="items.length === 0" class="text-center p-4">
      <Empty message="Không có dữ liệu" />
    </div>
    
    <table v-else class="table table-striped">
      <thead>
        <tr>
          <th v-for="column in columns" :key="column.key">
            {{ column.title }}
          </th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="item in items" :key="item.id">
          <td v-for="column in columns" :key="column.key">
            <slot 
              :name="column.key" 
              :item="item" 
              :value="item[column.key]"
            >
              {{ item[column.key] }}
            </slot>
          </td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script setup>
const props = defineProps({
  items: {
    type: Array,
    default: () => []
  },
  columns: {
    type: Array,
    required: true
  },
  loading: {
    type: Boolean,
    default: false
  }
})
</script>
```

## Component Communication
```vue
<!-- Parent Component -->
<template>
  <UserForm 
    :user="selectedUser"
    @save="handleSave"
    @cancel="handleCancel"
  />
</template>

<script setup>
const handleSave = (userData) => {
  // Handle save logic
  console.log('Saving user:', userData)
}

const handleCancel = () => {
  // Handle cancel logic
  console.log('Canceled')
}
</script>
```

## Loading States
```vue
<template>
  <div class="component-container">
    <div v-if="loading" class="loading-overlay">
      <Loader />
    </div>
    
    <div v-else class="content">
      <!-- Main content -->
    </div>
  </div>
</template>

<script setup>
const loading = ref(false)

const fetchData = async () => {
  loading.value = true
  try {
    // API call
  } finally {
    loading.value = false
  }
}
</script>
```

## Error Handling trong Components
```vue
<template>
  <div class="component">
    <div v-if="error" class="alert alert-danger">
      {{ error }}
      <button @click="retry" class="btn btn-sm btn-outline-danger ms-2">
        Thử lại
      </button>
    </div>
    
    <!-- Main content -->
  </div>
</template>

<script setup>
const error = ref(null)

const retry = () => {
  error.value = null
  fetchData()
}

const fetchData = async () => {
  try {
    // API call
  } catch (err) {
    error.value = err.message || 'Có lỗi xảy ra'
  }
}
</script>
```

## Component Export Pattern
```javascript
// components/index.js
export { default as LadaDialog } from './dialogs/ladaDialog.vue'
export { default as LadaAccordion } from './accordion/index.vue'
export { default as Pager } from './pagination/pager.vue'
export { default as Loader } from './loader.vue'
export { default as LadaDrawer } from './drawer/LadaDrawer.vue'
export { default as Blockui } from './blockui/blockui.vue'
export { default as Empty } from './Empty.vue'
export { default as OrderStatus } from './orders/status.vue'
export { default as LoadingOverlay } from './loaders/LoadingOverlay.vue'
```