fix: solve edit + add pages
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
height: 200
|
||||
height?: number
|
||||
activeTab?: 1 | 2
|
||||
}>()
|
||||
|
||||
@@ -12,7 +12,7 @@ function handleClick(value: 1 | 2) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="content-switcher" :style="`height: ${height}px`">
|
||||
<div class="content-switcher" :style="`height: ${height || 200}px`">
|
||||
<div :class="`${activeTab === 1 ? 'active' : 'inactive'}`">
|
||||
<div class="content-wrapper">
|
||||
<div>
|
||||
@@ -49,7 +49,7 @@ function handleClick(value: 1 | 2) {
|
||||
}
|
||||
|
||||
.content-wrapper {
|
||||
@apply p-4 2xl:p-5 overflow-hidden
|
||||
@apply p-4 2xl:p-5 overflow-hidden grow
|
||||
}
|
||||
.inactive .content-wrapper {
|
||||
@apply p-0 w-0
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
<script setup lang="ts">
|
||||
import type { LinkItem, ListItemDto } from './types'
|
||||
import { ActionEvents } from './types'
|
||||
|
||||
const props = defineProps<{
|
||||
rec: ListItemDto
|
||||
}>()
|
||||
|
||||
const recId = inject<Ref<number>>('rec_id')!
|
||||
const recAction = inject<Ref<string>>('rec_action')!
|
||||
const recItem = inject<Ref<any>>('rec_item')!
|
||||
const activeKey = ref<string | null>(null)
|
||||
const linkItems: LinkItem[] = [
|
||||
{
|
||||
label: 'Detail',
|
||||
onClick: () => {
|
||||
detail()
|
||||
},
|
||||
icon: 'i-lucide-eye',
|
||||
},
|
||||
{
|
||||
label: 'Print',
|
||||
onClick: () => {
|
||||
print()
|
||||
},
|
||||
icon: 'i-lucide-printer',
|
||||
},
|
||||
]
|
||||
|
||||
function detail() {
|
||||
recId.value = props.rec.id || 0
|
||||
recAction.value = ActionEvents.showDetail
|
||||
recItem.value = props.rec
|
||||
}
|
||||
|
||||
function print() {
|
||||
recId.value = props.rec.id || 0
|
||||
recAction.value = ActionEvents.showPrint
|
||||
recItem.value = props.rec
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<SidebarMenuButton
|
||||
size="lg"
|
||||
class="data-[state=open]:text-sidebar-accent-foreground data-[state=open]:bg-white dark:data-[state=open]:bg-slate-800"
|
||||
>
|
||||
<Icon
|
||||
name="i-lucide-chevrons-up-down"
|
||||
class="ml-auto size-4"
|
||||
/>
|
||||
</SidebarMenuButton>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
class="w-[--radix-dropdown-menu-trigger-width] min-w-40 rounded-lg border border-slate-200 bg-white text-black dark:border-slate-700 dark:bg-slate-800 dark:text-white"
|
||||
align="end"
|
||||
>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem
|
||||
v-for="item in linkItems"
|
||||
:key="item.label"
|
||||
class="hover:bg-gray-100 dark:hover:bg-slate-700"
|
||||
@click="item.onClick"
|
||||
@mouseenter="activeKey = item.label"
|
||||
@mouseleave="activeKey = null"
|
||||
>
|
||||
<Icon :name="item.icon ?? ''" />
|
||||
<span :class="activeKey === item.label ? 'text-sidebar-accent-foreground' : ''">{{ item.label }}</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,106 @@
|
||||
<script setup lang="ts">
|
||||
import type { LinkItem, ListItemDto } from './types'
|
||||
import { ActionEvents } from './types'
|
||||
|
||||
const props = defineProps<{
|
||||
rec: ListItemDto
|
||||
}>()
|
||||
|
||||
const recId = inject<Ref<number>>('rec_id')!
|
||||
const recAction = inject<Ref<string>>('rec_action')!
|
||||
const recItem = inject<Ref<any>>('rec_item')!
|
||||
const timestamp = inject<Ref<any>>('timestamp')!
|
||||
|
||||
const activeKey = ref<string | null>(null)
|
||||
const linkItems: LinkItem[] = [
|
||||
{
|
||||
label: 'Detail',
|
||||
onClick: () => {
|
||||
detail()
|
||||
},
|
||||
icon: 'i-lucide-eye',
|
||||
},
|
||||
{
|
||||
label: 'Edit',
|
||||
onClick: () => {
|
||||
edit()
|
||||
},
|
||||
icon: 'i-lucide-pencil',
|
||||
},
|
||||
{
|
||||
label: 'Verifikasi',
|
||||
onClick: () => {
|
||||
verify()
|
||||
},
|
||||
icon: 'i-lucide-shield-check',
|
||||
},
|
||||
{
|
||||
label: 'Print',
|
||||
onClick: () => {
|
||||
print()
|
||||
},
|
||||
icon: 'i-lucide-printer',
|
||||
},
|
||||
]
|
||||
|
||||
function detail() {
|
||||
recId.value = props.rec.id || 0
|
||||
recAction.value = ActionEvents.showDetail
|
||||
recItem.value = props.rec
|
||||
}
|
||||
|
||||
function edit() {
|
||||
recId.value = props.rec.id || 0
|
||||
recAction.value = ActionEvents.showEdit
|
||||
recItem.value = props.rec
|
||||
}
|
||||
|
||||
function verify() {
|
||||
recId.value = props.rec.id || 0
|
||||
recAction.value = ActionEvents.showConfirmVerify
|
||||
recItem.value = props.rec
|
||||
timestamp.value = new Date().getTime()
|
||||
}
|
||||
|
||||
function print() {
|
||||
recId.value = props.rec.id || 0
|
||||
recAction.value = ActionEvents.showPrint
|
||||
recItem.value = props.rec
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<SidebarMenuButton
|
||||
size="lg"
|
||||
class="data-[state=open]:text-sidebar-accent-foreground data-[state=open]:bg-white dark:data-[state=open]:bg-slate-800"
|
||||
>
|
||||
<Icon
|
||||
name="i-lucide-chevrons-up-down"
|
||||
class="ml-auto size-4"
|
||||
/>
|
||||
</SidebarMenuButton>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
class="w-[--radix-dropdown-menu-trigger-width] min-w-40 rounded-lg border border-slate-200 bg-white text-black dark:border-slate-700 dark:bg-slate-800 dark:text-white"
|
||||
align="end"
|
||||
>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem
|
||||
v-for="item in linkItems"
|
||||
:key="item.label"
|
||||
class="hover:bg-gray-100 dark:hover:bg-slate-700"
|
||||
@click="item.onClick"
|
||||
@mouseenter="activeKey = item.label"
|
||||
@mouseleave="activeKey = null"
|
||||
>
|
||||
<Icon :name="item.icon ?? ''" />
|
||||
<span :class="activeKey === item.label ? 'text-sidebar-accent-foreground' : ''">{{ item.label }}</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,64 @@
|
||||
<script setup lang="ts">
|
||||
import type { LinkItem, ListItemDto } from './types'
|
||||
import { ActionEvents } from './types'
|
||||
|
||||
const props = defineProps<{
|
||||
rec: ListItemDto
|
||||
}>()
|
||||
|
||||
const recId = inject<Ref<number>>('rec_id')!
|
||||
const recAction = inject<Ref<string>>('rec_action')!
|
||||
const recItem = inject<Ref<any>>('rec_item')!
|
||||
const activeKey = ref<string | null>(null)
|
||||
const linkItems: LinkItem[] = [
|
||||
{
|
||||
label: 'Process',
|
||||
onClick: () => {
|
||||
process()
|
||||
},
|
||||
icon: 'i-lucide-arrow-right',
|
||||
},
|
||||
]
|
||||
|
||||
function process() {
|
||||
recId.value = props.rec.id || 0
|
||||
recAction.value = ActionEvents.showProcess
|
||||
recItem.value = props.rec
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<SidebarMenuButton
|
||||
size="lg"
|
||||
class="data-[state=open]:text-sidebar-accent-foreground data-[state=open]:bg-white dark:data-[state=open]:bg-slate-800"
|
||||
>
|
||||
<Icon
|
||||
name="i-lucide-chevrons-up-down"
|
||||
class="ml-auto size-4"
|
||||
/>
|
||||
</SidebarMenuButton>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent
|
||||
class="w-[--radix-dropdown-menu-trigger-width] min-w-40 rounded-lg border border-slate-200 bg-white text-black dark:border-slate-700 dark:bg-slate-800 dark:text-white"
|
||||
align="end"
|
||||
>
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem
|
||||
v-for="item in linkItems"
|
||||
:key="item.label"
|
||||
class="hover:bg-gray-100 dark:hover:bg-slate-700"
|
||||
@click="item.onClick"
|
||||
@mouseenter="activeKey = item.label"
|
||||
@mouseleave="activeKey = null"
|
||||
>
|
||||
<Icon :name="item.icon ?? ''" />
|
||||
<span :class="activeKey === item.label ? 'text-sidebar-accent-foreground' : ''">{{ item.label }}</span>
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,30 @@
|
||||
<script setup lang="ts">
|
||||
import { ActionEvents, type ListItemDto } from '~/components/pub/my-ui/data/types';
|
||||
|
||||
const props = defineProps<{
|
||||
url: string
|
||||
btnTxt?: string
|
||||
rec: ListItemDto
|
||||
}>()
|
||||
|
||||
const recId = inject<Ref<number>>('rec_id')!
|
||||
const recAction = inject<Ref<string>>('rec_action')!
|
||||
const recItem = inject<Ref<any>>('rec_item')!
|
||||
const timestamp = inject<Ref<any>>('timestamp')!
|
||||
|
||||
function handlePrint() {
|
||||
recId.value = props.rec.id || 0
|
||||
recAction.value = ActionEvents.showPrint
|
||||
recItem.value = props.rec
|
||||
timestamp.value = new Date().toISOString()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Button
|
||||
class="gap-3 items-center border-orange-400 text-orange-400"
|
||||
variant="outline" @click="handlePrint">
|
||||
<Icon name="i-lucide-printer" class="h-4 w-4" />
|
||||
{{ props.btnTxt || 'Preview' }}
|
||||
</Button>
|
||||
</template>
|
||||
@@ -87,7 +87,9 @@ export const ActionEvents = {
|
||||
showProcess: 'showProcess',
|
||||
showCancel: 'showCancel',
|
||||
showVerify: 'showVerify',
|
||||
showConfirmVerify: 'showConfirmVerify',
|
||||
showValidate: 'showValidate',
|
||||
showConfirmVerify: 'showConfirmVerify',
|
||||
showPrint: 'showPrint',
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<script lang="ts" setup>
|
||||
|
||||
const { class: classProp } = defineProps<{
|
||||
class?: string
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="w-5 text-center">:</div>
|
||||
<div :class="`w-4 ps-1 ${classProp}`">:</div>
|
||||
</template>
|
||||
|
||||
@@ -47,7 +47,7 @@ function handleInput(event: Event) {
|
||||
<template>
|
||||
<DE.Cell :col-span="colSpan || 1">
|
||||
<DE.Label
|
||||
class="mb-1"
|
||||
class="font-medium mb-1"
|
||||
v-if="label !== ''"
|
||||
:label-for="fieldName"
|
||||
:is-required="isRequired && !isDisabled"
|
||||
@@ -69,7 +69,7 @@ function handleInput(event: Event) {
|
||||
v-bind="componentField"
|
||||
:placeholder="placeholder"
|
||||
:maxlength="maxLength"
|
||||
:class="cn('focus:border-primary focus:ring-2 focus:ring-primary focus:ring-offset-0')"
|
||||
:class="cn('focus:border-primary focus:ring-2 focus:ring-primary focus:ring-offset-0', props.class)"
|
||||
autocomplete="off"
|
||||
aria-autocomplete="none"
|
||||
autocorrect="off"
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
import { cn } from '~/lib/utils';
|
||||
|
||||
const props = defineProps<{
|
||||
label: string
|
||||
class?: string
|
||||
labelClass?: string
|
||||
}>()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex flex-col gap-1 lg:grid lg:grid-cols-[180px_minmax(0,1fr)] lg:gap-x-3">
|
||||
<div :class="cn(`flex flex-col gap-1 lg:grid lg:grid-cols-[180px_minmax(0,1fr)] lg:gap-x-3`, props.class)">
|
||||
<!-- Label -->
|
||||
<span class="text-md font-normal text-muted-foreground">
|
||||
<span :class="cn(`text-md font-normal text-muted-foreground`, props.labelClass)">
|
||||
{{ label }}
|
||||
</span>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import { type EncounterItem } from "../../../../handlers/encounter-process.handler";
|
||||
import { type EncounterItem } from "~/handlers/encounter-init.handler";
|
||||
|
||||
const props = defineProps<{
|
||||
initialActiveMenu: string
|
||||
@@ -18,22 +18,28 @@ function changeMenu(value: string) {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mt-4 flex gap-4">
|
||||
<div class="flex">
|
||||
<!-- Menu Sidebar -->
|
||||
<div v-if="data.length > 0" class="w-72 flex-shrink-0 rounded-md border bg-white shadow-sm dark:bg-neutral-950">
|
||||
<div class="max-h-[calc(100vh-12rem)] overflow-y-auto p-2">
|
||||
<button v-for="menu in data" :key="menu.id" :data-active="activeMenu === menu.id"
|
||||
class="w-full rounded-md px-4 py-3 text-left text-sm transition-colors data-[active=false]:text-gray-700 data-[active=false]:hover:bg-gray-100 data-[active=true]:bg-primary data-[active=true]:text-white dark:data-[active=false]:text-gray-300 dark:data-[active=false]:hover:bg-neutral-800"
|
||||
<div v-if="data.length > 0" class="w-56 2xl:w-64 flex-shrink-0 rounded-md border bg-white dark:bg-slate-800 shadow-sm">
|
||||
<div class="max-h-[calc(100vh-12rem)] overflow-y-auto px-2 py-3">
|
||||
<button
|
||||
v-for="menu in data"
|
||||
:key="menu.id"
|
||||
:data-active="activeMenu === menu.id"
|
||||
class="w-full rounded-md px-4 py-3 text-left text-xs 2xl:text-sm transition-colors data-[active=false]:text-gray-700 data-[active=false]:hover:bg-gray-100 data-[active=true]:bg-primary data-[active=true]:text-white dark:data-[active=false]:text-gray-300 dark:data-[active=false]:hover:bg-neutral-800"
|
||||
@click="changeMenu(menu.id)">
|
||||
{{ menu.title }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Active Menu Content -->
|
||||
<div v-if="data.find((m) => m.id === activeMenu)?.component"
|
||||
class="flex-1 rounded-md border bg-white p-4 shadow-sm dark:bg-neutral-950">
|
||||
<component :is="data.find((m) => m.id === activeMenu)?.component"
|
||||
v-bind="data.find((m) => m.id === activeMenu)?.props" />
|
||||
<div class="p-4 2xl:p-5 flex-grow">
|
||||
<div v-if="data.find((m) => m.id === activeMenu)?.component"
|
||||
class="flex-1 rounded-md border bg-white p-4 shadow-sm dark:bg-neutral-950">
|
||||
<component
|
||||
:is="data.find((m) => m.id === activeMenu)?.component"
|
||||
v-bind="data.find((m) => m.id === activeMenu)?.props" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -45,15 +45,12 @@ const isOpen = computed({
|
||||
|
||||
<template>
|
||||
<Dialog v-model:open="isOpen">
|
||||
<DialogContent
|
||||
:class="sizeClass"
|
||||
@interact-outside="(e: any) => preventOutside && e.preventDefault()"
|
||||
@pointer-down-outside="(e: any) => preventOutside && e.preventDefault()"
|
||||
>
|
||||
<DialogContent :class="sizeClass" @interact-outside="(e: any) => preventOutside && e.preventDefault()"
|
||||
@pointer-down-outside="(e: any) => preventOutside && e.preventDefault()">
|
||||
<DialogHeader>
|
||||
<DialogTitle :class="`text-sm 2xl:text-base font-semibold flex ${titleClass || ''}`">
|
||||
<div v-if="props.titleIcon" class="me-2 pt-0.5">
|
||||
<Icon :name="props.titleIcon" :class="`!pt-2`" />
|
||||
<div class="me-2 pt-0.5">
|
||||
<Icon v-if="props.titleIcon" :name="props.titleIcon" :class="`!pt-2`" />
|
||||
</div>
|
||||
<div>
|
||||
{{ props.title }}
|
||||
@@ -66,4 +63,4 @@ const isOpen = computed({
|
||||
</DialogDescription>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</template>
|
||||
</template>
|
||||
@@ -20,7 +20,7 @@ function onClick(type: ClickType) {
|
||||
@click="onClick('draft')"
|
||||
class="flex items-center gap-2 rounded-full border border-orange-400 bg-orange-50 px-3 py-1 text-sm font-medium text-orange-600 hover:bg-orange-100"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
{{ props.label }}
|
||||
|
||||
@@ -26,7 +26,7 @@ function onClick(type: ClickType) {
|
||||
<div :class="`${defaultClass} ${additionalClass} ${btnClass}`">
|
||||
<div>
|
||||
<Button variant="ghost" type="button" @click="onClick('back')">
|
||||
<Icon name="i-lucide-arrow-left" />
|
||||
<Icon name="i-lucide-arrow-left" />
|
||||
Back
|
||||
</Button>
|
||||
</div>
|
||||
@@ -38,7 +38,7 @@ function onClick(type: ClickType) {
|
||||
</div>
|
||||
<div>
|
||||
<Button type="button" @click="onClick('submit')">
|
||||
<Icon name="i-lucide-check" />
|
||||
<Icon name="i-lucide-check" />
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -50,8 +50,11 @@ const value = ref({
|
||||
end: todayCalendar,
|
||||
}) as Ref<DateRange>
|
||||
|
||||
|
||||
function onInput(event: Event) {
|
||||
props.refSearchNav?.onInput((event.target as HTMLInputElement).value)
|
||||
}
|
||||
function onFilterClick() {
|
||||
console.log('Search:', searchQuery.value)
|
||||
console.log('Date Range:', dateRange.value)
|
||||
props.refSearchNav?.onClick()
|
||||
}
|
||||
@@ -60,9 +63,11 @@ function onFilterClick() {
|
||||
<template>
|
||||
<header>
|
||||
<div class="flex items-center gap-2 mb-4 2xl:mb-5">
|
||||
<div class="relative w-64">
|
||||
|
||||
<div v-if="refSearchNav" class="relative w-64">
|
||||
<Search class="absolute left-3 top-1/2 size-4 -translate-y-1/2 text-gray-400" />
|
||||
<Input v-model="searchQuery" type="text" placeholder="Cari Nama /No.RM" class="pl-9" />
|
||||
<Input v-model="searchQuery" @input="onInput"
|
||||
type="text" placeholder="Cari .." class="pl-9" />
|
||||
</div>
|
||||
|
||||
<Popover>
|
||||
@@ -101,7 +106,7 @@ function onFilterClick() {
|
||||
</Button>
|
||||
|
||||
<DropdownMenu v-show="props.enableExport">
|
||||
<DropdownMenuTrigger as-child>
|
||||
<DropdownMenuTrigger v-show="props.enableExport" as-child>
|
||||
<Button variant="outline" class="ml-auto border-orange-500 text-orange-600 hover:bg-orange-50">
|
||||
<Icon name="i-lucide-download" class="h-4 w-4" />
|
||||
Ekspor
|
||||
|
||||
@@ -37,6 +37,10 @@ function btnClick() {
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<!-- For components as slots -->
|
||||
<slot />
|
||||
|
||||
<!-- For components passed by props -->
|
||||
<div v-if="prep.components">
|
||||
<template v-for="cwp in prep.components">
|
||||
<component
|
||||
|
||||
@@ -32,7 +32,7 @@ function btnClick() {
|
||||
/>
|
||||
</div>
|
||||
<div v-if="prep.addNav" class="m-2 flex items-center">
|
||||
<Button size="md" class="rounded-md border border-gray-300 px-4 py-2 text-white sm:text-sm" @click="btnClick">
|
||||
<Button size="default" class="rounded-md border border-gray-300 px-4 py-2 text-white sm:text-sm" @click="btnClick">
|
||||
<Icon name="i-lucide-plus" class="mr-2 h-4 w-4 align-middle" />
|
||||
{{ prep.addNav.label }}
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user