composables: cherry-pick

This commit is contained in:
Khafid Prayoga
2025-12-08 11:32:18 +07:00
parent dcbc9682df
commit b5846adb7e
2 changed files with 83 additions and 27 deletions
+28 -8
View File
@@ -2,7 +2,6 @@ import type { DataTableLoader } from '~/components/pub/my-ui/data-table/type'
import type { PaginationMeta } from '~/components/pub/my-ui/pagination/pagination.type'
import { refDebounced, useUrlSearchParams } from '@vueuse/core'
import * as z from 'zod'
import { is } from "date-fns/locale"
// Default query schema yang bisa digunakan semua list
export const defaultQuerySchema = z.object({
@@ -38,10 +37,23 @@ interface UsePaginatedListOptions<T = any> {
}>
// Nama endpoint untuk logging error
entityName: string
/**
* Apakah state harus disinkronkan ke URL Browser?
* Set `false` jika digunakan di dalam Modal, Drawer, atau Nested Component
* agar tidak menimpa URL halaman induk.
* @default true
*/
syncToUrl?: boolean
}
export function usePaginatedList<T = any>(options: UsePaginatedListOptions<T>) {
const { querySchema = defaultQuerySchema, defaultQuery = defaultQueryParams, fetchFn, entityName } = options
const {
querySchema = defaultQuerySchema,
defaultQuery = defaultQueryParams,
fetchFn,
entityName,
syncToUrl = true, // Default true agar behavior lama tetap jalan
} = options
// State management
const data = ref<T[]>([])
@@ -49,11 +61,19 @@ export function usePaginatedList<T = any>(options: UsePaginatedListOptions<T>) {
isTableLoading: false,
})
// URL state management
const queryParams = useUrlSearchParams('history', {
initialValue: defaultQuery,
removeFalsyValues: true,
})
let queryParams: any
if (syncToUrl) {
// Mode Halaman Utama: Sync ke URL
queryParams = useUrlSearchParams('history', {
initialValue: defaultQuery,
removeFalsyValues: true,
write: false,
})
} else {
// Mode Nested/Modal: Local Reactive State
queryParams = reactive({ ...defaultQuery })
}
const params = computed(() => {
const result = querySchema.safeParse(queryParams)
@@ -168,7 +188,7 @@ export function usePaginatedList<T = any>(options: UsePaginatedListOptions<T>) {
}
}
export function transform(endpoint: string ,params: any): string {
export function transform(endpoint: string, params: any): string {
const urlParams = new URLSearchParams()
Object.entries(params).forEach(([key, value]) => {
+55 -19
View File
@@ -3,18 +3,18 @@ import { useRoute, useRouter } from 'vue-router'
export function useQueryCRUD(modeKey: string = 'mode', recordIdKey: string = 'record-id') {
type params = {
mode: string,
mode: string
recordId: any
}
const route = useRoute()
const router = useRouter()
const crudQueryParams = computed<params> ({
const crudQueryParams = computed<params>({
get: () => {
return {
mode: route.query[modeKey] && route.query[modeKey] === 'entry' ? 'entry' : 'list',
recordId: route.query[recordIdKey]
recordId: route.query[recordIdKey],
}
},
set: (val) => {
@@ -30,17 +30,15 @@ export function useQueryCRUD(modeKey: string = 'mode', recordIdKey: string = 're
})
const goToEntry = (myRecord_id?: any) => {
if(myRecord_id) {
crudQueryParams.value = { mode: 'entry', recordId: myRecord_id }
if (myRecord_id) {
crudQueryParams.value.mode = 'entry'
crudQueryParams.value.recordId = myRecord_id
} else {
crudQueryParams.value = { mode: 'entry', recordId: undefined }
crudQueryParams.value.mode = 'entry'
crudQueryParams.value.recordId = undefined
}
}
const goToDetail = (myRecord_id: string|number) => {
crudQueryParams.value = { mode: 'list', recordId: String(myRecord_id) }
}
const backToList = () => {
delete route.query[recordIdKey]
router.push({
@@ -52,15 +50,22 @@ export function useQueryCRUD(modeKey: string = 'mode', recordIdKey: string = 're
})
}
return { crudQueryParams, goToEntry, goToDetail, backToList }
return { crudQueryParams, goToEntry, backToList }
}
export function useQueryCRUDMode(key: string = 'mode') {
const route = useRoute()
const router = useRouter()
const mode = computed<'list' | 'entry'>({
get: () => (route.query[key] && route.query[key] === 'entry' ? 'entry' : 'list'),
const mode = computed<'list' | 'entry' | 'view'>({
get: () => {
const q = route.query[key]
if (q === 'entry') return 'entry'
if (q === 'view') return 'view'
return 'list'
},
set: (val) => {
router.push({
path: route.path,
@@ -72,9 +77,22 @@ export function useQueryCRUDMode(key: string = 'mode') {
},
})
const goToEntry = (myRecord_id?: any) => {
mode.value = 'entry'
if(myRecord_id) {
const fromView = computed(() => route.query['from'] === 'view')
const goToEntry = (options?: { fromView?: boolean }) => {
router.push({
path: route.path,
query: {
...route.query,
[key]: 'entry',
from: options?.fromView ? 'view' : undefined,
},
})
}
const goToView = (myRecord_id?: any) => {
mode.value = 'view'
if (myRecord_id) {
myRecord_id.value = myRecord_id
}
}
@@ -85,13 +103,32 @@ export function useQueryCRUDMode(key: string = 'mode') {
query: {
...route.query,
mode: 'list',
// HAPUS record-id
recordIdKey: undefined,
from: undefined,
},
})
}
return { mode, goToEntry, backToList }
const backToView = () => {
router.push({
path: route.path,
query: {
...route.query,
mode: 'view',
from: undefined,
},
})
}
const goBack = () => {
if (fromView.value) {
backToView()
} else {
backToList()
}
}
return { mode, fromView, goToEntry, goToView, backToList, backToView, goBack }
}
export function useQueryCRUDRecordId(key: string = 'record-id') {
@@ -114,4 +151,3 @@ export function useQueryCRUDRecordId(key: string = 'record-id') {
return { recordId }
}