123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. <script setup>
  2. import { ref, watch, onMounted } from 'vue'
  3. import { Inertia } from '@inertiajs/inertia'
  4. import { Head, useForm } from '@inertiajs/inertia-vue3'
  5. import dayjs from 'dayjs'
  6. import pickBy from 'lodash/pickBy'
  7. import AppButton from '@/components/AppButton.vue'
  8. import AppPagination from '@/components/AppPagination.vue'
  9. import AppMenu from '@/components/AppMenu.vue'
  10. import AppDropdown from '@/components/AppDropdown.vue'
  11. import AppLayout from '@/layouts/AppLayout.vue'
  12. import { IndexTable } from './TableHeader'
  13. const props = defineProps({
  14. transactions: Object,
  15. transactionsStatus: Array,
  16. filters: Object,
  17. outlets: Array,
  18. })
  19. const filterForm = useForm({
  20. search: props.filters.search,
  21. dates: null,
  22. startDate: props.filters.startDate,
  23. endDate: props.filters.endDate,
  24. outlet: props.filters.outlet,
  25. })
  26. onMounted(() => {
  27. if (props.filters.startDate || props.filters.endDate) {
  28. if (props.filters.endDate) {
  29. filterForm.dates = [new Date(props.filters.startDate), new Date(props.filters.endDate)]
  30. } else {
  31. filterForm.dates = [new Date(props.filters.startDate), null]
  32. }
  33. }
  34. })
  35. watch(filterForm, () => {
  36. if (filterForm.dates) {
  37. if (filterForm.dates[1]) {
  38. filterForm.startDate = dayjs(filterForm.dates[0]).format('YYYY-MM-DD')
  39. filterForm.endDate = dayjs(filterForm.dates[1]).format('YYYY-MM-DD')
  40. } else {
  41. filterForm.startDate = dayjs(filterForm.dates[0]).format('YYYY-MM-DD')
  42. filterForm.endDate = null
  43. }
  44. } else {
  45. filterForm.endDate = null
  46. filterForm.startDate = null
  47. }
  48. Inertia.get(
  49. '/transactions',
  50. pickBy({
  51. search: filterForm.search,
  52. startDate: filterForm.startDate,
  53. endDate: filterForm.endDate,
  54. outlet: filterForm.outlet,
  55. }),
  56. {
  57. preserveState: true,
  58. }
  59. )
  60. })
  61. const filterReset = () => {
  62. Inertia.get('/transactions')
  63. }
  64. const transactionId = ref()
  65. const updateStatusDialogShow = ref(false)
  66. const updateStatusForm = useForm({
  67. transaction_status_id: null,
  68. })
  69. const updateStatusSubmit = () => {
  70. updateStatusForm.put(route('transactions.update', transactionId.value), {
  71. onSuccess: () => {
  72. updateStatusDialogShow.value = false
  73. },
  74. })
  75. }
  76. const updateStatusItems = ref([])
  77. const overlayMenu = ref()
  78. const overlayItems = ref([])
  79. const startPrinting = (transactionNumber) => {
  80. Inertia.get(`/thermal-printing/${transactionNumber}`)
  81. }
  82. const overlayToggle = (event, data) => {
  83. overlayItems.value =
  84. data.transactionStatusId == 4
  85. ? [
  86. {
  87. label: 'Lihat detail',
  88. icon: 'pi pi-eye',
  89. to: route('transactions.show', data.id),
  90. },
  91. {
  92. label: 'Cetak ulang',
  93. icon: 'pi pi-print',
  94. command() {
  95. startPrinting(data.transactionNumber)
  96. },
  97. },
  98. ]
  99. : [
  100. {
  101. label: 'Perbaharui status',
  102. icon: 'pi pi-refresh',
  103. command() {
  104. updateStatusDialogShow.value = true
  105. },
  106. },
  107. {
  108. label: 'Lihat detail',
  109. icon: 'pi pi-eye',
  110. to: route('transactions.show', data.id),
  111. },
  112. {
  113. label: 'Cetak ulang',
  114. icon: 'pi pi-print',
  115. command() {
  116. startPrinting(data.transactionNumber)
  117. },
  118. },
  119. ]
  120. updateStatusItems.value = props.transactionsStatus.filter((val) => val.value >= data.transactionStatusId)
  121. updateStatusForm.transaction_status_id = data.transactionStatusId
  122. transactionId.value = data.id
  123. overlayMenu.value.toggle(event)
  124. }
  125. </script>
  126. <template>
  127. <Head title="Daftar Transaksi" />
  128. <AppLayout>
  129. <DataTable
  130. responsive-layout="scroll"
  131. column-resize-mode="expand"
  132. :value="transactions.data"
  133. :row-hover="true"
  134. :striped-rows="true"
  135. >
  136. <template #header>
  137. <h1>Transaksi</h1>
  138. <div class="grid">
  139. <div class="col-12 md:col-8">
  140. <div class="grid">
  141. <div class="col-12 md:col-3">
  142. <InputText class="w-full" placeholder="cari..." v-model="filterForm.search" />
  143. </div>
  144. <div class="col-12 md:col-3">
  145. <Calendar
  146. class="w-full"
  147. v-model="filterForm.dates"
  148. selection-mode="range"
  149. placeholder="filter waktu..."
  150. date-format="dd/mm/yy"
  151. :manual-input="false"
  152. />
  153. </div>
  154. <div v-if="$page.props.auth.user.role_id === 1" class="col-12 md:col-3">
  155. <Dropdown
  156. class="w-full"
  157. placeholder="pilih outlet..."
  158. v-model="filterForm.outlet"
  159. option-label="label"
  160. option-value="value"
  161. :options="outlets"
  162. />
  163. </div>
  164. <div class="col-auto mt-2 ml-2">
  165. <Button label="reset" class="p-button-link" @click="filterReset" />
  166. </div>
  167. </div>
  168. </div>
  169. <div
  170. v-if="$page.props.auth.user.role_id !== 1"
  171. class="col-12 md:col-4 flex flex-column md:flex-row justify-content-end"
  172. >
  173. <AppButton
  174. label="Tambah Transaksi"
  175. class="p-button-outlined md:w-16rem"
  176. icon="pi pi-pencil"
  177. :href="route('transactions.create')"
  178. />
  179. </div>
  180. </div>
  181. </template>
  182. <Column
  183. v-for="indexTable in IndexTable"
  184. :field="indexTable.field"
  185. :header="indexTable.header"
  186. :key="indexTable.field"
  187. >
  188. <template #body="{ data, field }">
  189. <template v-if="field === 'transactionNumber'">
  190. <p class="font-bold">{{ data[field] }}</p>
  191. <p>{{ data.createdAt }}</p>
  192. </template>
  193. <template v-else-if="field === 'customer'">
  194. <p class="font-bold">{{ data.customer.number }}</p>
  195. <p>{{ data.customer.name }}</p>
  196. <p>{{ data.customer.phone }}</p>
  197. </template>
  198. <template v-else-if="field === 'transactionStatusName'">
  199. <Badge v-if="data['transactionStatusId'] === 1" :value="data[field]"></Badge>
  200. <Badge v-else-if="data['transactionStatusId'] === 2" :value="data[field]" severity="warning"></Badge>
  201. <Badge v-else :value="data[field]" severity="success"></Badge>
  202. </template>
  203. <template v-else>
  204. {{ data[field] }}
  205. </template>
  206. </template>
  207. </Column>
  208. <Column>
  209. <template #body="slotProps">
  210. <Button
  211. icon="pi pi-angle-double-down"
  212. class="p-button-rounded p-button-text"
  213. aria-controls="overlay_menu"
  214. @click="overlayToggle($event, slotProps.data)"
  215. />
  216. <AppMenu id="overlay_menu" ref="overlayMenu" :popup="true" :model="overlayItems" />
  217. </template>
  218. </Column>
  219. </DataTable>
  220. <AppPagination :links="transactions.links" />
  221. <Dialog
  222. modal
  223. v-model:visible="updateStatusDialogShow"
  224. class="p-fluid"
  225. header="Perbaharui Status"
  226. :style="{ width: '450px' }"
  227. :breakpoints="{ '960px': '75vw' }"
  228. @hide="updateStatusDialogShow"
  229. >
  230. <div class="grid">
  231. <div class="col-12">
  232. <AppDropdown
  233. label="Perbaharui Status"
  234. placeholder="pilih satu"
  235. v-model="updateStatusForm.transaction_status_id"
  236. :error="updateStatusForm.error"
  237. :options="updateStatusItems"
  238. />
  239. </div>
  240. </div>
  241. <template #footer>
  242. <div class="flex justify-content-end">
  243. <Button
  244. label="Simpan"
  245. icon="pi pi-check"
  246. class="p-button-text"
  247. :disabled="updateStatusForm.processing"
  248. @click="updateStatusSubmit"
  249. />
  250. </div>
  251. </template>
  252. </Dialog>
  253. </AppLayout>
  254. </template>