Merge remote-tracking branch 'origin/dev' into fe-refactor-division-40

This commit is contained in:
Khafid Prayoga
2025-09-17 11:09:39 +07:00
46 changed files with 2944 additions and 180 deletions
@@ -15,6 +15,7 @@ const props = defineProps<{
searchPlaceholder?: string
emptyMessage?: string
class?: string
disabled?: boolean
}>()
const emit = defineEmits<{
@@ -63,13 +64,14 @@ function onSelect(item: Item) {
<PopoverTrigger as-child>
<Button
:id="props.id"
:disabled="props.disabled"
variant="outline"
role="combobox"
:aria-expanded="open"
:aria-controls="`${props.id}-list`"
:aria-describedby="`${props.id}-search`"
:class="cn(
'w-full justify-between border-black bg-white hover:bg-gray-50 text-sm font-normal',
'w-full justify-between border-1 border-gray-400 bg-white hover:bg-gray-50 text-sm font-normal focus:outline-none focus:ring-1 focus:ring-black',
!modelValue && 'text-muted-foreground',
props.class,
)"
@@ -0,0 +1,56 @@
<script setup lang="ts">
// helpers
import { format, parseISO } from 'date-fns'
// components
import { Button } from '~/components/pub/ui/button'
import { Calendar } from '~/components/pub/ui/calendar'
import { Popover, PopoverContent, PopoverTrigger } from '~/components/pub/ui/popover'
const props = defineProps<{
placeholder?: string
modelValue?: Date | string | undefined
}>()
const emit = defineEmits<{
'update:modelValue': [value: Date | string | undefined]
}>()
const date = ref<Date | any>(undefined)
watch(date, (value) => {
const newValue = format(value, 'yyyy-MM-dd')
emit('update:modelValue', newValue)
})
onMounted(() => {
if (props.modelValue) {
const value = props.modelValue
if (value instanceof Date) {
date.value = value
} else if (typeof value === 'string' && value) {
date.value = parseISO(value)
} else {
date.value = undefined
}
}
})
</script>
<template>
<div class="flex flex-col space-y-2">
<Popover>
<PopoverTrigger as-child>
<Button variant="outline" class="bg-white border-gray-400 font-normal text-right h-[40px] w-full">
<div class="flex justify-between items-center w-full">
<p v-if="date">{{ format(date, 'PPP') }}</p>
<p v-else class="text-sm text-black text-opacity-50">{{ props.placeholder || 'Tanggal' }}</p>
<Icon name="i-lucide-calendar" class="h-5 w-5" />
</div>
</Button>
</PopoverTrigger>
<PopoverContent class="w-auto p-0">
<Calendar v-model="date" mode="single" />
</PopoverContent>
</Popover>
</div>
</template>
+5 -8
View File
@@ -54,8 +54,10 @@ function onValueChange(value: string) {
<template>
<SelectRoot :model-value="modelValue" @update:model-value="onValueChange">
<SelectTrigger :class="cn('w-full', props.class)">
<SelectValue :placeholder="placeholder || 'Pilih item'" />
<SelectTrigger :class="cn('w-full focus:outline-none focus:ring-1 focus:ring-black bg-white', props.class)">
<SelectValue :placeholder="placeholder || 'Pilih item'" :class="cn(
props.modelValue ? 'text-black' : 'text-muted-foreground',
)" />
</SelectTrigger>
<SelectContent>
@@ -64,12 +66,7 @@ function onValueChange(value: string) {
{{ label }}
</SelectLabel>
<SelectItem
v-for="item in sortedItems"
:key="item.value"
:value="item.value"
class="cursor-pointer"
>
<SelectItem v-for="item in sortedItems" :key="item.value" :value="item.value" class="cursor-pointer">
<div class="flex items-center justify-between w-full">
<span>{{ item.label }}</span>
<span v-if="item.code" class="text-xs text-muted-foreground ml-2">
@@ -0,0 +1,24 @@
<script setup lang="ts">
import type { PaginationMeta } from '~/components/pub/custom-ui/pagination/pagination.type'
import Pagination from './pagination.vue'
const props = defineProps<{
paginationMeta: PaginationMeta
}>()
const emit = defineEmits<{
pageChange: [page: number]
}>()
function handlePageChange(page: number) {
emit('pageChange', page)
}
</script>
<template>
<Pagination
v-if="props.paginationMeta && props.paginationMeta.pageSize > 0"
:pagination-meta="paginationMeta"
@page-change="handlePageChange"
/>
</template>
@@ -65,7 +65,8 @@ const formattedRecordCount = computed(() => {
})
const startRecord = computed(() => {
return ((props.paginationMeta.page - 1) * props.paginationMeta.pageSize) + 1
const start = ((props.paginationMeta.page - 1) * props.paginationMeta.pageSize) + 1
return Number(start).toLocaleString('id-ID')
})
const endRecord = computed(() => {
@@ -89,12 +90,12 @@ function getButtonClass(pageNumber: number) {
<template>
<div class="flex items-center justify-between px-2 py-2 w-full min-w-0">
<!-- Info text -->
<div v-if="showInfo" class="text-sm text-muted-foreground shrink-0">
<div v-if="showInfo && endRecord > 0" class="text-sm text-muted-foreground shrink-0">
Menampilkan {{ startRecord }}
hingga {{ endRecord }}
hingga {{ Number(endRecord).toLocaleString('id-ID') }}
dari {{ formattedRecordCount }} data
</div>
<div v-else class="shrink-0"></div>
<div v-else class="shrink-0">-</div>
<!-- Spacer untuk memastikan ada ruang di tengah -->
<div class="flex-1 min-w-4"></div>
@@ -28,7 +28,7 @@ const iconName = computed(() => props.iconName || 'i-radix-icons-caret-sort')
>
<slot />
<SelectIcon as-child class="absolute right-3 top-1/2 -translate-y-1/2">
<Icon name="i-radix-icons-caret-sort" class="h-4 w-4 opacity-50" />
<Icon :name="iconName" class="h-4 w-4 opacity-50" />
</SelectIcon>
</SelectTrigger>
</template>