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