News.vue 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. <script setup lang="ts">
  2. import { defineAsyncComponent, ref } from "vue";
  3. import Toast from "toasters";
  4. import { useWebsocketsStore } from "@/stores/websockets";
  5. import { useModalsStore } from "@/stores/modals";
  6. import { TableColumn, TableFilter, TableEvents } from "@/types/advancedTable";
  7. const AdvancedTable = defineAsyncComponent(
  8. () => import("@/components/AdvancedTable.vue")
  9. );
  10. const QuickConfirm = defineAsyncComponent(
  11. () => import("@/components/QuickConfirm.vue")
  12. );
  13. const UserLink = defineAsyncComponent(
  14. () => import("@/components/UserLink.vue")
  15. );
  16. const { socket } = useWebsocketsStore();
  17. const columnDefault = ref(<TableColumn>{
  18. sortable: true,
  19. hidable: true,
  20. defaultVisibility: "shown",
  21. draggable: true,
  22. resizable: true,
  23. minWidth: 150,
  24. maxWidth: 600
  25. });
  26. const columns = ref(<TableColumn[]>[
  27. {
  28. name: "options",
  29. displayName: "Options",
  30. properties: ["_id"],
  31. sortable: false,
  32. hidable: false,
  33. resizable: false,
  34. minWidth: 85,
  35. defaultWidth: 85
  36. },
  37. {
  38. name: "status",
  39. displayName: "Status",
  40. properties: ["status"],
  41. sortProperty: "status",
  42. defaultWidth: 150
  43. },
  44. {
  45. name: "showToNewUsers",
  46. displayName: "Show to new users",
  47. properties: ["showToNewUsers"],
  48. sortProperty: "showToNewUsers",
  49. defaultWidth: 180
  50. },
  51. {
  52. name: "title",
  53. displayName: "Title",
  54. properties: ["title"],
  55. sortProperty: "title"
  56. },
  57. {
  58. name: "createdBy",
  59. displayName: "Created By",
  60. properties: ["createdBy"],
  61. sortProperty: "createdBy",
  62. defaultWidth: 150
  63. },
  64. {
  65. name: "markdown",
  66. displayName: "Markdown",
  67. properties: ["markdown"],
  68. sortProperty: "markdown"
  69. }
  70. ]);
  71. const filters = ref(<TableFilter[]>[
  72. {
  73. name: "status",
  74. displayName: "Status",
  75. property: "status",
  76. filterTypes: ["contains", "exact", "regex"],
  77. defaultFilterType: "contains"
  78. },
  79. {
  80. name: "showToNewUsers",
  81. displayName: "Show to new users",
  82. property: "showToNewUsers",
  83. filterTypes: ["boolean"],
  84. defaultFilterType: "boolean"
  85. },
  86. {
  87. name: "title",
  88. displayName: "Title",
  89. property: "title",
  90. filterTypes: ["contains", "exact", "regex"],
  91. defaultFilterType: "contains"
  92. },
  93. {
  94. name: "createdBy",
  95. displayName: "Created By",
  96. property: "createdBy",
  97. filterTypes: ["contains", "exact", "regex"],
  98. defaultFilterType: "contains"
  99. },
  100. {
  101. name: "markdown",
  102. displayName: "Markdown",
  103. property: "markdown",
  104. filterTypes: ["contains", "exact", "regex"],
  105. defaultFilterType: "contains"
  106. }
  107. ]);
  108. const events = ref(<TableEvents>{
  109. adminRoom: "news",
  110. updated: {
  111. event: "admin.news.updated",
  112. id: "news._id",
  113. item: "news"
  114. },
  115. removed: {
  116. event: "admin.news.deleted",
  117. id: "newsId"
  118. }
  119. });
  120. const { openModal } = useModalsStore();
  121. const remove = id => {
  122. socket.dispatch("news.remove", id, res => new Toast(res.message));
  123. };
  124. </script>
  125. <template>
  126. <div class="admin-tab container">
  127. <page-metadata title="Admin | News" />
  128. <div class="card tab-info">
  129. <div class="info-row">
  130. <h1>News</h1>
  131. <p>Create and update news items</p>
  132. </div>
  133. <div class="button-row">
  134. <button
  135. class="is-primary button"
  136. @click="
  137. openModal({
  138. modal: 'editNews',
  139. data: { createNews: true }
  140. })
  141. "
  142. >
  143. Create News Item
  144. </button>
  145. </div>
  146. </div>
  147. <advanced-table
  148. :column-default="columnDefault"
  149. :columns="columns"
  150. :filters="filters"
  151. data-action="news.getData"
  152. name="admin-news"
  153. :max-width="1200"
  154. :events="events"
  155. >
  156. <template #column-options="slotProps">
  157. <div class="row-options">
  158. <button
  159. class="button is-primary icon-with-button material-icons"
  160. @click="
  161. openModal({
  162. modal: 'editNews',
  163. data: { newsId: slotProps.item._id }
  164. })
  165. "
  166. content="Edit News"
  167. v-tippy
  168. >
  169. edit
  170. </button>
  171. <quick-confirm
  172. @confirm="remove(slotProps.item._id)"
  173. :disabled="slotProps.item.removed"
  174. >
  175. <button
  176. class="button is-danger icon-with-button material-icons"
  177. content="Remove News"
  178. v-tippy
  179. >
  180. delete_forever
  181. </button>
  182. </quick-confirm>
  183. </div>
  184. </template>
  185. <template #column-status="slotProps">
  186. <span :title="slotProps.item.status">{{
  187. slotProps.item.status
  188. }}</span>
  189. </template>
  190. <template #column-showToNewUsers="slotProps">
  191. <span :title="slotProps.item.showToNewUsers">{{
  192. slotProps.item.showToNewUsers
  193. }}</span>
  194. </template>
  195. <template #column-title="slotProps">
  196. <span :title="slotProps.item.title">{{
  197. slotProps.item.title
  198. }}</span>
  199. </template>
  200. <template #column-createdBy="slotProps">
  201. <user-link
  202. :user-id="slotProps.item.createdBy"
  203. :alt="slotProps.item.createdBy"
  204. />
  205. </template>
  206. <template #column-markdown="slotProps">
  207. <span :title="slotProps.item.markdown">{{
  208. slotProps.item.markdown
  209. }}</span>
  210. </template>
  211. </advanced-table>
  212. </div>
  213. </template>