diff --git a/package-lock.json b/package-lock.json index dfa0ef9..e5738d1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,7 @@ "@inertiajs/vue3": "^3.0.0", "@lucide/vue": "^1.17.0", "@tailwindcss/vite": "^4.1.11", + "@tanstack/vue-table": "^8.21.3", "@vitejs/plugin-vue": "^6.0.0", "@vueuse/core": "^14.3.0", "class-variance-authority": "^0.7.1", @@ -1202,6 +1203,19 @@ "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, + "node_modules/@tanstack/table-core": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/table-core/-/table-core-8.21.3.tgz", + "integrity": "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@tanstack/virtual-core": { "version": "3.17.0", "resolved": "https://registry.npmjs.org/@tanstack/virtual-core/-/virtual-core-3.17.0.tgz", @@ -1212,6 +1226,25 @@ "url": "https://github.com/sponsors/tannerlinsley" } }, + "node_modules/@tanstack/vue-table": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@tanstack/vue-table/-/vue-table-8.21.3.tgz", + "integrity": "sha512-rusRyd77c5tDPloPskctMyPLFEQUeBzxdQ+2Eow4F7gDPlPOB1UnnhzfpdvqZ8ZyX2rRNGmqNnQWm87OI2OQPw==", + "license": "MIT", + "dependencies": { + "@tanstack/table-core": "8.21.3" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "vue": ">=3.2" + } + }, "node_modules/@tanstack/vue-virtual": { "version": "3.13.28", "resolved": "https://registry.npmjs.org/@tanstack/vue-virtual/-/vue-virtual-3.13.28.tgz", diff --git a/package.json b/package.json index c521657..f9211bb 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@inertiajs/vue3": "^3.0.0", "@lucide/vue": "^1.17.0", "@tailwindcss/vite": "^4.1.11", + "@tanstack/vue-table": "^8.21.3", "@vitejs/plugin-vue": "^6.0.0", "@vueuse/core": "^14.3.0", "class-variance-authority": "^0.7.1", diff --git a/resources/js/components/AppSidebar.vue b/resources/js/components/AppSidebar.vue index 6ad3e3f..1d11bcb 100644 --- a/resources/js/components/AppSidebar.vue +++ b/resources/js/components/AppSidebar.vue @@ -1,6 +1,6 @@ @@ -51,6 +52,21 @@ const isDashboardActive = computed(() => page.url.startsWith('/admin/dashboard') + + HR + + + + + + + Pegawai + + + + + + diff --git a/resources/js/components/data-table/DataTable.vue b/resources/js/components/data-table/DataTable.vue new file mode 100644 index 0000000..7b7bc7f --- /dev/null +++ b/resources/js/components/data-table/DataTable.vue @@ -0,0 +1,138 @@ + + + + + emit('filter-change', key, value)" + @filters-reset="emit('filters-reset')" /> + + + + + + + + + + + + + + + + + + + + + + Data tidak ditemukan + + Silakan lakukan pencarian atau filter untuk menemukan data yang Anda cari. + + + + + + + + + diff --git a/resources/js/components/data-table/DataTableColumnHeader.vue b/resources/js/components/data-table/DataTableColumnHeader.vue new file mode 100644 index 0000000..fc03d86 --- /dev/null +++ b/resources/js/components/data-table/DataTableColumnHeader.vue @@ -0,0 +1,51 @@ + + + + + + {{ title }} + + + + + + diff --git a/resources/js/components/data-table/DataTableToolbar.vue b/resources/js/components/data-table/DataTableToolbar.vue new file mode 100644 index 0000000..19d856c --- /dev/null +++ b/resources/js/components/data-table/DataTableToolbar.vue @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + Filter + + {{ activeFilterCount }} + + + + + + + Filter + + + Sesuaikan filter untuk mempersempit data. + + + + + {{ filter.label }} + + + + + + + + + + Semua + + + {{ option.label }} + + + + + + + Reset Filter + + + + + diff --git a/resources/js/components/data-table/index.ts b/resources/js/components/data-table/index.ts new file mode 100644 index 0000000..bfe57e5 --- /dev/null +++ b/resources/js/components/data-table/index.ts @@ -0,0 +1,3 @@ +export { default as DataTable } from './DataTable.vue'; +export { default as DataTableColumnHeader } from './DataTableColumnHeader.vue'; +export { default as DataTableToolbar } from './DataTableToolbar.vue'; diff --git a/resources/js/components/ui/alert-dialog/AlertDialog.vue b/resources/js/components/ui/alert-dialog/AlertDialog.vue new file mode 100644 index 0000000..b6e6b4b --- /dev/null +++ b/resources/js/components/ui/alert-dialog/AlertDialog.vue @@ -0,0 +1,15 @@ + + + + + + + diff --git a/resources/js/components/ui/alert-dialog/AlertDialogAction.vue b/resources/js/components/ui/alert-dialog/AlertDialogAction.vue new file mode 100644 index 0000000..09cf6fc --- /dev/null +++ b/resources/js/components/ui/alert-dialog/AlertDialogAction.vue @@ -0,0 +1,18 @@ + + + + + + + diff --git a/resources/js/components/ui/alert-dialog/AlertDialogCancel.vue b/resources/js/components/ui/alert-dialog/AlertDialogCancel.vue new file mode 100644 index 0000000..e261894 --- /dev/null +++ b/resources/js/components/ui/alert-dialog/AlertDialogCancel.vue @@ -0,0 +1,25 @@ + + + + + + + diff --git a/resources/js/components/ui/alert-dialog/AlertDialogContent.vue b/resources/js/components/ui/alert-dialog/AlertDialogContent.vue new file mode 100644 index 0000000..4597f0d --- /dev/null +++ b/resources/js/components/ui/alert-dialog/AlertDialogContent.vue @@ -0,0 +1,44 @@ + + + + + + + + + + diff --git a/resources/js/components/ui/alert-dialog/AlertDialogDescription.vue b/resources/js/components/ui/alert-dialog/AlertDialogDescription.vue new file mode 100644 index 0000000..69642c9 --- /dev/null +++ b/resources/js/components/ui/alert-dialog/AlertDialogDescription.vue @@ -0,0 +1,23 @@ + + + + + + + diff --git a/resources/js/components/ui/alert-dialog/AlertDialogFooter.vue b/resources/js/components/ui/alert-dialog/AlertDialogFooter.vue new file mode 100644 index 0000000..50d4098 --- /dev/null +++ b/resources/js/components/ui/alert-dialog/AlertDialogFooter.vue @@ -0,0 +1,22 @@ + + + + + + + diff --git a/resources/js/components/ui/alert-dialog/AlertDialogHeader.vue b/resources/js/components/ui/alert-dialog/AlertDialogHeader.vue new file mode 100644 index 0000000..dbe72a7 --- /dev/null +++ b/resources/js/components/ui/alert-dialog/AlertDialogHeader.vue @@ -0,0 +1,17 @@ + + + + + + + diff --git a/resources/js/components/ui/alert-dialog/AlertDialogTitle.vue b/resources/js/components/ui/alert-dialog/AlertDialogTitle.vue new file mode 100644 index 0000000..bb97e4d --- /dev/null +++ b/resources/js/components/ui/alert-dialog/AlertDialogTitle.vue @@ -0,0 +1,21 @@ + + + + + + + diff --git a/resources/js/components/ui/alert-dialog/AlertDialogTrigger.vue b/resources/js/components/ui/alert-dialog/AlertDialogTrigger.vue new file mode 100644 index 0000000..98d40ee --- /dev/null +++ b/resources/js/components/ui/alert-dialog/AlertDialogTrigger.vue @@ -0,0 +1,12 @@ + + + + + + + diff --git a/resources/js/components/ui/alert-dialog/index.ts b/resources/js/components/ui/alert-dialog/index.ts new file mode 100644 index 0000000..cf1b45d --- /dev/null +++ b/resources/js/components/ui/alert-dialog/index.ts @@ -0,0 +1,9 @@ +export { default as AlertDialog } from "./AlertDialog.vue" +export { default as AlertDialogAction } from "./AlertDialogAction.vue" +export { default as AlertDialogCancel } from "./AlertDialogCancel.vue" +export { default as AlertDialogContent } from "./AlertDialogContent.vue" +export { default as AlertDialogDescription } from "./AlertDialogDescription.vue" +export { default as AlertDialogFooter } from "./AlertDialogFooter.vue" +export { default as AlertDialogHeader } from "./AlertDialogHeader.vue" +export { default as AlertDialogTitle } from "./AlertDialogTitle.vue" +export { default as AlertDialogTrigger } from "./AlertDialogTrigger.vue" diff --git a/resources/js/components/ui/badge/Badge.vue b/resources/js/components/ui/badge/Badge.vue new file mode 100644 index 0000000..d894dfe --- /dev/null +++ b/resources/js/components/ui/badge/Badge.vue @@ -0,0 +1,26 @@ + + + + + + + diff --git a/resources/js/components/ui/badge/index.ts b/resources/js/components/ui/badge/index.ts new file mode 100644 index 0000000..635c961 --- /dev/null +++ b/resources/js/components/ui/badge/index.ts @@ -0,0 +1,26 @@ +import type { VariantProps } from "class-variance-authority" +import { cva } from "class-variance-authority" + +export { default as Badge } from "./Badge.vue" + +export const badgeVariants = cva( + "inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90", + secondary: + "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", + destructive: + "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + }, +) +export type BadgeVariants = VariantProps diff --git a/resources/js/components/ui/empty/Empty.vue b/resources/js/components/ui/empty/Empty.vue new file mode 100644 index 0000000..2637b3c --- /dev/null +++ b/resources/js/components/ui/empty/Empty.vue @@ -0,0 +1,20 @@ + + + + + + + diff --git a/resources/js/components/ui/empty/EmptyContent.vue b/resources/js/components/ui/empty/EmptyContent.vue new file mode 100644 index 0000000..d19ee00 --- /dev/null +++ b/resources/js/components/ui/empty/EmptyContent.vue @@ -0,0 +1,20 @@ + + + + + + + diff --git a/resources/js/components/ui/empty/EmptyDescription.vue b/resources/js/components/ui/empty/EmptyDescription.vue new file mode 100644 index 0000000..e4ed5fb --- /dev/null +++ b/resources/js/components/ui/empty/EmptyDescription.vue @@ -0,0 +1,20 @@ + + + + + + + diff --git a/resources/js/components/ui/empty/EmptyHeader.vue b/resources/js/components/ui/empty/EmptyHeader.vue new file mode 100644 index 0000000..ac21d8c --- /dev/null +++ b/resources/js/components/ui/empty/EmptyHeader.vue @@ -0,0 +1,20 @@ + + + + + + + diff --git a/resources/js/components/ui/empty/EmptyMedia.vue b/resources/js/components/ui/empty/EmptyMedia.vue new file mode 100644 index 0000000..c68397c --- /dev/null +++ b/resources/js/components/ui/empty/EmptyMedia.vue @@ -0,0 +1,21 @@ + + + + + + + diff --git a/resources/js/components/ui/empty/EmptyTitle.vue b/resources/js/components/ui/empty/EmptyTitle.vue new file mode 100644 index 0000000..90c950d --- /dev/null +++ b/resources/js/components/ui/empty/EmptyTitle.vue @@ -0,0 +1,17 @@ + + + + + + + diff --git a/resources/js/components/ui/empty/index.ts b/resources/js/components/ui/empty/index.ts new file mode 100644 index 0000000..ce0c489 --- /dev/null +++ b/resources/js/components/ui/empty/index.ts @@ -0,0 +1,26 @@ +import type { VariantProps } from "class-variance-authority" +import { cva } from "class-variance-authority" + +export { default as Empty } from "./Empty.vue" +export { default as EmptyContent } from "./EmptyContent.vue" +export { default as EmptyDescription } from "./EmptyDescription.vue" +export { default as EmptyHeader } from "./EmptyHeader.vue" +export { default as EmptyMedia } from "./EmptyMedia.vue" +export { default as EmptyTitle } from "./EmptyTitle.vue" + +export const emptyMediaVariants = cva( + "mb-2 flex shrink-0 items-center justify-center [&_svg]:pointer-events-none [&_svg]:shrink-0", + { + variants: { + variant: { + default: "bg-transparent", + icon: "bg-muted text-foreground flex size-10 shrink-0 items-center justify-center rounded-lg [&_svg:not([class*='size-'])]:size-6", + }, + }, + defaultVariants: { + variant: "default", + }, + }, +) + +export type EmptyMediaVariants = VariantProps diff --git a/resources/js/components/ui/phone-number-input/PhoneNumberInput.vue b/resources/js/components/ui/phone-number-input/PhoneNumberInput.vue new file mode 100644 index 0000000..a5aa4a0 --- /dev/null +++ b/resources/js/components/ui/phone-number-input/PhoneNumberInput.vue @@ -0,0 +1,38 @@ + + + + + diff --git a/resources/js/components/ui/phone-number-input/index.ts b/resources/js/components/ui/phone-number-input/index.ts new file mode 100644 index 0000000..5e25646 --- /dev/null +++ b/resources/js/components/ui/phone-number-input/index.ts @@ -0,0 +1 @@ +export { default as PhoneNumberInput } from './PhoneNumberInput.vue'; diff --git a/resources/js/components/ui/popover/Popover.vue b/resources/js/components/ui/popover/Popover.vue new file mode 100644 index 0000000..4efdb98 --- /dev/null +++ b/resources/js/components/ui/popover/Popover.vue @@ -0,0 +1,19 @@ + + + + + + + diff --git a/resources/js/components/ui/popover/PopoverAnchor.vue b/resources/js/components/ui/popover/PopoverAnchor.vue new file mode 100644 index 0000000..49e01db --- /dev/null +++ b/resources/js/components/ui/popover/PopoverAnchor.vue @@ -0,0 +1,15 @@ + + + + + + + diff --git a/resources/js/components/ui/popover/PopoverContent.vue b/resources/js/components/ui/popover/PopoverContent.vue new file mode 100644 index 0000000..cf1e55c --- /dev/null +++ b/resources/js/components/ui/popover/PopoverContent.vue @@ -0,0 +1,45 @@ + + + + + + + + + diff --git a/resources/js/components/ui/popover/PopoverTrigger.vue b/resources/js/components/ui/popover/PopoverTrigger.vue new file mode 100644 index 0000000..fd3b497 --- /dev/null +++ b/resources/js/components/ui/popover/PopoverTrigger.vue @@ -0,0 +1,15 @@ + + + + + + + diff --git a/resources/js/components/ui/popover/index.ts b/resources/js/components/ui/popover/index.ts new file mode 100644 index 0000000..66edf89 --- /dev/null +++ b/resources/js/components/ui/popover/index.ts @@ -0,0 +1,4 @@ +export { default as Popover } from "./Popover.vue" +export { default as PopoverAnchor } from "./PopoverAnchor.vue" +export { default as PopoverContent } from "./PopoverContent.vue" +export { default as PopoverTrigger } from "./PopoverTrigger.vue" diff --git a/resources/js/components/ui/radio-group/RadioGroup.vue b/resources/js/components/ui/radio-group/RadioGroup.vue new file mode 100644 index 0000000..54045c4 --- /dev/null +++ b/resources/js/components/ui/radio-group/RadioGroup.vue @@ -0,0 +1,25 @@ + + + + + + + diff --git a/resources/js/components/ui/radio-group/RadioGroupItem.vue b/resources/js/components/ui/radio-group/RadioGroupItem.vue new file mode 100644 index 0000000..1a2142f --- /dev/null +++ b/resources/js/components/ui/radio-group/RadioGroupItem.vue @@ -0,0 +1,40 @@ + + + + + + + + + + + diff --git a/resources/js/components/ui/radio-group/index.ts b/resources/js/components/ui/radio-group/index.ts new file mode 100644 index 0000000..7cb0e3b --- /dev/null +++ b/resources/js/components/ui/radio-group/index.ts @@ -0,0 +1,2 @@ +export { default as RadioGroup } from "./RadioGroup.vue" +export { default as RadioGroupItem } from "./RadioGroupItem.vue" diff --git a/resources/js/components/ui/rupiah-input/RupiahInput.vue b/resources/js/components/ui/rupiah-input/RupiahInput.vue new file mode 100644 index 0000000..a683907 --- /dev/null +++ b/resources/js/components/ui/rupiah-input/RupiahInput.vue @@ -0,0 +1,45 @@ + + + + + + Rp + + + + diff --git a/resources/js/components/ui/rupiah-input/index.ts b/resources/js/components/ui/rupiah-input/index.ts new file mode 100644 index 0000000..5a33596 --- /dev/null +++ b/resources/js/components/ui/rupiah-input/index.ts @@ -0,0 +1 @@ +export { default as RupiahInput } from './RupiahInput.vue'; diff --git a/resources/js/components/ui/select/Select.vue b/resources/js/components/ui/select/Select.vue new file mode 100644 index 0000000..c94bbe8 --- /dev/null +++ b/resources/js/components/ui/select/Select.vue @@ -0,0 +1,19 @@ + + + + + + + diff --git a/resources/js/components/ui/select/SelectContent.vue b/resources/js/components/ui/select/SelectContent.vue new file mode 100644 index 0000000..adf04ec --- /dev/null +++ b/resources/js/components/ui/select/SelectContent.vue @@ -0,0 +1,51 @@ + + + + + + + + + + + + + diff --git a/resources/js/components/ui/select/SelectGroup.vue b/resources/js/components/ui/select/SelectGroup.vue new file mode 100644 index 0000000..e981c6c --- /dev/null +++ b/resources/js/components/ui/select/SelectGroup.vue @@ -0,0 +1,15 @@ + + + + + + + diff --git a/resources/js/components/ui/select/SelectItem.vue b/resources/js/components/ui/select/SelectItem.vue new file mode 100644 index 0000000..a6a0dd3 --- /dev/null +++ b/resources/js/components/ui/select/SelectItem.vue @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + diff --git a/resources/js/components/ui/select/SelectItemText.vue b/resources/js/components/ui/select/SelectItemText.vue new file mode 100644 index 0000000..b6700b1 --- /dev/null +++ b/resources/js/components/ui/select/SelectItemText.vue @@ -0,0 +1,15 @@ + + + + + + + diff --git a/resources/js/components/ui/select/SelectLabel.vue b/resources/js/components/ui/select/SelectLabel.vue new file mode 100644 index 0000000..5b6650c --- /dev/null +++ b/resources/js/components/ui/select/SelectLabel.vue @@ -0,0 +1,17 @@ + + + + + + + diff --git a/resources/js/components/ui/select/SelectScrollDownButton.vue b/resources/js/components/ui/select/SelectScrollDownButton.vue new file mode 100644 index 0000000..62c9c9e --- /dev/null +++ b/resources/js/components/ui/select/SelectScrollDownButton.vue @@ -0,0 +1,26 @@ + + + + + + + + + diff --git a/resources/js/components/ui/select/SelectScrollUpButton.vue b/resources/js/components/ui/select/SelectScrollUpButton.vue new file mode 100644 index 0000000..b27afe8 --- /dev/null +++ b/resources/js/components/ui/select/SelectScrollUpButton.vue @@ -0,0 +1,26 @@ + + + + + + + + + diff --git a/resources/js/components/ui/select/SelectSeparator.vue b/resources/js/components/ui/select/SelectSeparator.vue new file mode 100644 index 0000000..4b5c885 --- /dev/null +++ b/resources/js/components/ui/select/SelectSeparator.vue @@ -0,0 +1,19 @@ + + + + + diff --git a/resources/js/components/ui/select/SelectTrigger.vue b/resources/js/components/ui/select/SelectTrigger.vue new file mode 100644 index 0000000..3715b43 --- /dev/null +++ b/resources/js/components/ui/select/SelectTrigger.vue @@ -0,0 +1,33 @@ + + + + + + + + + + diff --git a/resources/js/components/ui/select/SelectValue.vue b/resources/js/components/ui/select/SelectValue.vue new file mode 100644 index 0000000..d5ce58b --- /dev/null +++ b/resources/js/components/ui/select/SelectValue.vue @@ -0,0 +1,15 @@ + + + + + + + diff --git a/resources/js/components/ui/select/index.ts b/resources/js/components/ui/select/index.ts new file mode 100644 index 0000000..96eae60 --- /dev/null +++ b/resources/js/components/ui/select/index.ts @@ -0,0 +1,11 @@ +export { default as Select } from "./Select.vue" +export { default as SelectContent } from "./SelectContent.vue" +export { default as SelectGroup } from "./SelectGroup.vue" +export { default as SelectItem } from "./SelectItem.vue" +export { default as SelectItemText } from "./SelectItemText.vue" +export { default as SelectLabel } from "./SelectLabel.vue" +export { default as SelectScrollDownButton } from "./SelectScrollDownButton.vue" +export { default as SelectScrollUpButton } from "./SelectScrollUpButton.vue" +export { default as SelectSeparator } from "./SelectSeparator.vue" +export { default as SelectTrigger } from "./SelectTrigger.vue" +export { default as SelectValue } from "./SelectValue.vue" diff --git a/resources/js/components/ui/table/Table.vue b/resources/js/components/ui/table/Table.vue new file mode 100644 index 0000000..0d0cd9b --- /dev/null +++ b/resources/js/components/ui/table/Table.vue @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/resources/js/components/ui/table/TableBody.vue b/resources/js/components/ui/table/TableBody.vue new file mode 100644 index 0000000..d14a2d3 --- /dev/null +++ b/resources/js/components/ui/table/TableBody.vue @@ -0,0 +1,17 @@ + + + + + + + diff --git a/resources/js/components/ui/table/TableCaption.vue b/resources/js/components/ui/table/TableCaption.vue new file mode 100644 index 0000000..3630084 --- /dev/null +++ b/resources/js/components/ui/table/TableCaption.vue @@ -0,0 +1,17 @@ + + + + + + + diff --git a/resources/js/components/ui/table/TableCell.vue b/resources/js/components/ui/table/TableCell.vue new file mode 100644 index 0000000..3a83b7d --- /dev/null +++ b/resources/js/components/ui/table/TableCell.vue @@ -0,0 +1,22 @@ + + + + + + + diff --git a/resources/js/components/ui/table/TableEmpty.vue b/resources/js/components/ui/table/TableEmpty.vue new file mode 100644 index 0000000..a6fd6d0 --- /dev/null +++ b/resources/js/components/ui/table/TableEmpty.vue @@ -0,0 +1,34 @@ + + + + + + + + + + + diff --git a/resources/js/components/ui/table/TableFooter.vue b/resources/js/components/ui/table/TableFooter.vue new file mode 100644 index 0000000..29e0ce9 --- /dev/null +++ b/resources/js/components/ui/table/TableFooter.vue @@ -0,0 +1,17 @@ + + + + + + + diff --git a/resources/js/components/ui/table/TableHead.vue b/resources/js/components/ui/table/TableHead.vue new file mode 100644 index 0000000..3a2ea4c --- /dev/null +++ b/resources/js/components/ui/table/TableHead.vue @@ -0,0 +1,17 @@ + + + + + + + diff --git a/resources/js/components/ui/table/TableHeader.vue b/resources/js/components/ui/table/TableHeader.vue new file mode 100644 index 0000000..b4ab5cf --- /dev/null +++ b/resources/js/components/ui/table/TableHeader.vue @@ -0,0 +1,17 @@ + + + + + + + diff --git a/resources/js/components/ui/table/TableRow.vue b/resources/js/components/ui/table/TableRow.vue new file mode 100644 index 0000000..8f1d172 --- /dev/null +++ b/resources/js/components/ui/table/TableRow.vue @@ -0,0 +1,17 @@ + + + + + + + diff --git a/resources/js/components/ui/table/index.ts b/resources/js/components/ui/table/index.ts new file mode 100644 index 0000000..3be308b --- /dev/null +++ b/resources/js/components/ui/table/index.ts @@ -0,0 +1,9 @@ +export { default as Table } from "./Table.vue" +export { default as TableBody } from "./TableBody.vue" +export { default as TableCaption } from "./TableCaption.vue" +export { default as TableCell } from "./TableCell.vue" +export { default as TableEmpty } from "./TableEmpty.vue" +export { default as TableFooter } from "./TableFooter.vue" +export { default as TableHead } from "./TableHead.vue" +export { default as TableHeader } from "./TableHeader.vue" +export { default as TableRow } from "./TableRow.vue" diff --git a/resources/js/components/ui/table/utils.ts b/resources/js/components/ui/table/utils.ts new file mode 100644 index 0000000..3d4fd12 --- /dev/null +++ b/resources/js/components/ui/table/utils.ts @@ -0,0 +1,10 @@ +import type { Updater } from "@tanstack/vue-table" + +import type { Ref } from "vue" +import { isFunction } from "@tanstack/vue-table" + +export function valueUpdater(updaterOrValue: Updater, ref: Ref) { + ref.value = isFunction(updaterOrValue) + ? updaterOrValue(ref.value) + : updaterOrValue +} diff --git a/resources/js/components/ui/textarea/Textarea.vue b/resources/js/components/ui/textarea/Textarea.vue new file mode 100644 index 0000000..3a4ddf3 --- /dev/null +++ b/resources/js/components/ui/textarea/Textarea.vue @@ -0,0 +1,28 @@ + + + + + diff --git a/resources/js/components/ui/textarea/index.ts b/resources/js/components/ui/textarea/index.ts new file mode 100644 index 0000000..8ce91e9 --- /dev/null +++ b/resources/js/components/ui/textarea/index.ts @@ -0,0 +1 @@ +export { default as Textarea } from "./Textarea.vue" diff --git a/resources/js/composables/useDataTableQuery.ts b/resources/js/composables/useDataTableQuery.ts new file mode 100644 index 0000000..979ff2d --- /dev/null +++ b/resources/js/composables/useDataTableQuery.ts @@ -0,0 +1,85 @@ +import { router } from '@inertiajs/vue3'; +import { useDebounceFn } from '@vueuse/core'; +import { ref, watch, type WatchSource } from 'vue'; +import type { DataTableQuery, DataTableSort } from '@/types/data-table'; + +type UseDataTableQueryOptions = { + url: string; + initial: DataTableQuery; + filterKeys?: string[]; + debounceMs?: number; +}; + +function buildParams(query: DataTableQuery, filterKeys: string[]): Record { + const params: Record = { + search: query.search || undefined, + sort: query.sort || undefined, + direction: query.direction || undefined, + }; + + for (const key of filterKeys) { + params[key] = query[key] || undefined; + } + + return params; +} + +export function useDataTableQuery(options: UseDataTableQueryOptions) { + const filterKeys = options.filterKeys ?? []; + const query = ref({ ...options.initial }); + + const reload = useDebounceFn(() => { + router.get(options.url, buildParams(query.value, filterKeys), { + preserveState: true, + replace: true, + preserveScroll: true, + }); + }, options.debounceMs ?? 300); + + function setSearch(value: string): void { + query.value.search = value; + reload(); + } + + function setSort(sort: DataTableSort | null): void { + query.value.sort = sort?.column; + query.value.direction = sort?.direction; + reload(); + } + + function setFilter(key: string, value: string): void { + query.value[key] = value; + reload(); + } + + function resetFilters(): void { + for (const key of filterKeys) { + query.value[key] = ''; + } + + reload(); + } + + function syncFromServer(filters: DataTableQuery): void { + query.value = { ...filters }; + } + + return { + query, + setSearch, + setSort, + setFilter, + resetFilters, + reload, + syncFromServer, + }; +} + +export function useDataTableQuerySync( + filters: WatchSource, + syncFromServer: (filters: DataTableQuery) => void, +): void { + watch(filters, (value) => { + syncFromServer(value); + }); +} diff --git a/resources/js/lib/phone-number.ts b/resources/js/lib/phone-number.ts new file mode 100644 index 0000000..904a86c --- /dev/null +++ b/resources/js/lib/phone-number.ts @@ -0,0 +1,23 @@ +const MAX_PHONE_DIGITS = 13; + +export function parsePhoneNumber(value: string | number): string { + return String(value).replace(/\D/g, '').slice(0, MAX_PHONE_DIGITS); +} + +export function formatPhoneNumber(value: string | number): string { + const digits = parsePhoneNumber(value); + + if (!digits) { + return ''; + } + + if (digits.length <= 4) { + return digits; + } + + if (digits.length <= 8) { + return `${digits.slice(0, 4)}-${digits.slice(4)}`; + } + + return `${digits.slice(0, 4)}-${digits.slice(4, 8)}-${digits.slice(8)}`; +} diff --git a/resources/js/lib/rupiah.ts b/resources/js/lib/rupiah.ts new file mode 100644 index 0000000..08ac6cf --- /dev/null +++ b/resources/js/lib/rupiah.ts @@ -0,0 +1,13 @@ +export function parseRupiah(value: string | number): string { + return String(value).replace(/\D/g, ''); +} + +export function formatRupiah(value: string | number): string { + const digits = parseRupiah(value); + + if (!digits) { + return ''; + } + + return Number(digits).toLocaleString('id-ID'); +} diff --git a/resources/js/types/data-table.ts b/resources/js/types/data-table.ts new file mode 100644 index 0000000..8794f52 --- /dev/null +++ b/resources/js/types/data-table.ts @@ -0,0 +1,31 @@ +export type DataTableSort = { + column: string; + direction: 'asc' | 'desc'; +}; + +export type DataTableFilterOption = { + value: string; + label: string; +}; + +export type DataTableFilterDef = { + key: string; + label: string; + type: 'text' | 'select'; + placeholder?: string; + options?: DataTableFilterOption[]; +}; + +export type DataTablePagination = { + currentPage: number; + perPage: number; + lastPage: number; + total: number; +}; + +export type DataTableQuery = { + search?: string; + sort?: string; + direction?: 'asc' | 'desc'; + [key: string]: string | undefined; +}; diff --git a/resources/js/types/employee.ts b/resources/js/types/employee.ts new file mode 100644 index 0000000..5ce4ee9 --- /dev/null +++ b/resources/js/types/employee.ts @@ -0,0 +1,60 @@ +export type EnumOption = { + value: string; + label: string; +}; + +export type EmployeeListItem = { + id: number; + employee_code: string; + join_date: string | null; + resign_date: string | null; + employment_status: string; + employment_status_label: string; + employee_status: string; + employee_status_label: string; + base_salary: number; + base_salary_formatted: string; + email: string | null; + username: string | null; + is_active: boolean; + full_name: string | null; + phone_number: string | null; + gender: string | null; + gender_label: string | null; + birth_date: string | null; + address: string | null; +}; + +export type EmployeeFormData = { + email: string; + username: string; + full_name: string; + phone_number: string; + gender: string; + birth_date: string; + address: string; + join_date: string; + employment_status: string; + base_salary: string; +}; + +export type EmployeeFilters = { + search: string; + sort?: string; + direction?: 'asc' | 'desc' | null; + employment_status?: string; + employee_status?: string; +}; + +export type PaginatedEmployees = { + data: EmployeeListItem[]; + current_page: number; + last_page: number; + per_page: number; + total: number; + links: Array<{ + url: string | null; + label: string; + active: boolean; + }>; +};
+ Sesuaikan filter untuk mempersempit data. +
+ +