CreateStation.vue 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. <script setup lang="ts">
  2. import { useStore } from "vuex";
  3. import { ref, onBeforeUnmount } from "vue";
  4. import Toast from "toasters";
  5. import { storeToRefs } from "pinia";
  6. import { useWebsocketsStore } from "@/stores/websockets";
  7. import { useCreateStationStore } from "@/stores/createStation";
  8. import validation from "@/validation";
  9. const props = defineProps({
  10. modalUuid: { type: String, default: "" }
  11. });
  12. const store = useStore();
  13. const { socket } = useWebsocketsStore();
  14. const createStationStore = useCreateStationStore(props);
  15. const { official } = storeToRefs(createStationStore);
  16. const closeCurrentModal = () =>
  17. store.dispatch("modalVisibility/closeCurrentModal");
  18. const newStation = ref({
  19. name: "",
  20. displayName: "",
  21. description: ""
  22. });
  23. const submitModal = () => {
  24. newStation.value.name = newStation.value.name.toLowerCase();
  25. const { name, displayName, description } = newStation.value;
  26. if (!name || !displayName || !description)
  27. return new Toast("Please fill in all fields");
  28. if (!validation.isLength(name, 2, 16))
  29. return new Toast("Name must have between 2 and 16 characters.");
  30. if (!validation.regex.az09_.test(name))
  31. return new Toast(
  32. "Invalid name format. Allowed characters: a-z, 0-9 and _."
  33. );
  34. if (!validation.isLength(displayName, 2, 32))
  35. return new Toast("Display name must have between 2 and 32 characters.");
  36. if (!validation.regex.ascii.test(displayName))
  37. return new Toast(
  38. "Invalid display name format. Only ASCII characters are allowed."
  39. );
  40. if (!validation.isLength(description, 2, 200))
  41. return new Toast("Description must have between 2 and 200 characters.");
  42. let characters = description.split("");
  43. characters = characters.filter(
  44. character => character.charCodeAt(0) === 21328
  45. );
  46. if (characters.length !== 0)
  47. return new Toast("Invalid description format.");
  48. return socket.dispatch(
  49. "stations.create",
  50. {
  51. name,
  52. type: official.value ? "official" : "community",
  53. displayName,
  54. description
  55. },
  56. res => {
  57. if (res.status === "success") {
  58. new Toast(`You have added the station successfully`);
  59. closeCurrentModal();
  60. } else new Toast(res.message);
  61. }
  62. );
  63. };
  64. onBeforeUnmount(() => {
  65. // Delete the Pinia store that was created for this modal, after all other cleanup tasks are performed
  66. createStationStore.$dispose();
  67. });
  68. </script>
  69. <template>
  70. <modal
  71. :title="
  72. official ? 'Create Official Station' : 'Create Community Station'
  73. "
  74. >
  75. <template #body>
  76. <label class="label">Name (unique lowercase station id)</label>
  77. <p class="control">
  78. <input
  79. v-model="newStation.name"
  80. class="input station-id"
  81. type="text"
  82. placeholder="Name..."
  83. autofocus
  84. />
  85. </p>
  86. <label class="label">Display Name</label>
  87. <p class="control">
  88. <input
  89. v-model="newStation.displayName"
  90. class="input"
  91. type="text"
  92. placeholder="Display name..."
  93. />
  94. </p>
  95. <label class="label">Description</label>
  96. <p class="control">
  97. <input
  98. v-model="newStation.description"
  99. class="input"
  100. type="text"
  101. placeholder="Description..."
  102. @keyup.enter="submitModal()"
  103. />
  104. </p>
  105. </template>
  106. <template #footer>
  107. <a class="button is-primary" @click="submitModal()">Create</a>
  108. </template>
  109. </modal>
  110. </template>
  111. <style lang="less" scoped>
  112. .station-id {
  113. text-transform: lowercase;
  114. &::placeholder {
  115. text-transform: none;
  116. }
  117. }
  118. </style>