News.vue 5.1 KB

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