Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 

285 wiersze
7.1 KiB

  1. <template>
  2. <div
  3. class="modal fade"
  4. id="editBlogCat"
  5. tabindex="-1"
  6. role="dialog"
  7. aria-labelledby="exampleModalLabel"
  8. aria-hidden="true"
  9. >
  10. <div class="modal-dialog modal-sm" role="document">
  11. <div class="modal-content">
  12. <div class="modal-header">
  13. <h5 class="modal-title" id="exampleModalLabel">ویرایش کردن دسته</h5>
  14. <button
  15. type="button"
  16. class="btn-close"
  17. data-bs-dismiss="modal"
  18. aria-label="Close"
  19. ></button>
  20. </div>
  21. <div class="modal-body">
  22. <form @submit.prevent="editCat">
  23. <BRow class="g-3">
  24. <BCol lg="6">
  25. <div class="form-group">
  26. <label class="form-label">عنوان دسته</label>
  27. <input
  28. v-model="localTitle"
  29. @input="clearError('localTitle')"
  30. type="text"
  31. class="form-control"
  32. placeholder="عنوان دسته"
  33. :class="{ 'is-invalid': errors.localTitle }"
  34. />
  35. <small v-if="errors.localTitle" class="text-danger">
  36. {{ errors.localTitle }}
  37. </small>
  38. </div>
  39. </BCol>
  40. <BCol lg="6">
  41. <div class="form-group">
  42. <label class="form-label">انتخاب آیکن</label>
  43. <b-dropdown
  44. variant="outline-primary"
  45. class="w-100"
  46. @change="clearError('icon')"
  47. >
  48. <b-dropdown-item
  49. v-for="(icon, index) in iconData"
  50. :key="index"
  51. :value="icon.component"
  52. class="icon-item"
  53. @click="setSelectedIcon(icon.component)"
  54. >
  55. <div class="icon-container">
  56. <i :class="`ph-duotone ${icon.component}`"></i>
  57. </div>
  58. </b-dropdown-item>
  59. </b-dropdown>
  60. <div v-if="localIcon" class="mt-2">
  61. <label class="form-label">آیکن انتخاب شده:</label>
  62. <div class="selected-icon-container">
  63. <i :class="`ph-duotone ${localIcon}`"></i>
  64. </div>
  65. </div>
  66. <div v-if="!localIcon" class="mt-2">
  67. <label class="form-label">آیکن انتخاب شده:</label>
  68. <div class="selected-icon-container">
  69. <i :class="`ph-duotone ${localIcon}`"></i>
  70. </div>
  71. </div>
  72. <small v-if="errors.icon" class="text-danger">
  73. {{ errors.icon }}
  74. </small>
  75. </div>
  76. </BCol>
  77. </BRow>
  78. <!-- Submit Buttons -->
  79. <div
  80. class="d-flex justify-content-end gap-2"
  81. style="margin-top: 20px"
  82. >
  83. <button
  84. type="button"
  85. class="btn btn-secondary"
  86. data-bs-dismiss="modal"
  87. id="closeEditBlogCat"
  88. >
  89. بستن
  90. </button>
  91. <button type="submit" class="btn btn-primary" :disabled="loading">
  92. <span
  93. v-if="loading"
  94. class="spinner-border spinner-border-sm"
  95. role="status"
  96. aria-hidden="true"
  97. ></span>
  98. ذخیره
  99. </button>
  100. </div>
  101. </form>
  102. </div>
  103. </div>
  104. </div>
  105. </div>
  106. </template>
  107. <script>
  108. import { iconData } from "../../../views/live-preview/icon/data";
  109. import { ref, toRef, watch } from "vue";
  110. import { toast } from "vue3-toastify";
  111. import "vue3-toastify/dist/index.css";
  112. import ApiServiece from "@/services/ApiService";
  113. export default {
  114. props: {
  115. icon: {
  116. type: String,
  117. Required: true,
  118. },
  119. title: {
  120. type: String,
  121. Required: true,
  122. },
  123. id: {
  124. type: String,
  125. Required: true,
  126. },
  127. },
  128. setup(props, { emit }) {
  129. const localTitle = toRef(props.title);
  130. const localIcon = ref(props.icon);
  131. const localId = toRef(props.id);
  132. const errors = ref({});
  133. const loading = ref(false);
  134. watch(
  135. () => props.title,
  136. (newVal) => (localTitle.value = newVal)
  137. );
  138. watch(
  139. () => props.icon,
  140. (newVal) => (localIcon.value = newVal)
  141. );
  142. watch(
  143. () => props.id,
  144. (newVal) => (localId.value = newVal)
  145. );
  146. const clearError = (field) => {
  147. errors.value[field] = "";
  148. };
  149. const validateForm = () => {
  150. errors.value = {};
  151. if (!localTitle.value)
  152. errors.value.localTitle = "وارد کردن عنوان ضروری می باشد";
  153. if (!localIcon.value) errors.value.icon = "انتخاب آیکن ضروری است";
  154. return Object.keys(errors.value).length === 0;
  155. };
  156. const setSelectedIcon = (icon) => {
  157. localIcon.value = icon;
  158. };
  159. const editCat = () => {
  160. if (!validateForm()) return;
  161. loading.value = true;
  162. const formData = new FormData();
  163. formData.append("title", localTitle.value);
  164. formData.append("icon", localIcon.value);
  165. ApiServiece.put(`admin/blog-categories/${localId.value}`, formData)
  166. .then(() => {
  167. toast.success("!دسته با موفقیت ویرایش شد", {
  168. position: "top-right",
  169. autoClose: 1000,
  170. });
  171. })
  172. .then(() => {
  173. setTimeout(() => {
  174. document.getElementById("closeEditBlogCat").click();
  175. emit("cat-updated");
  176. }, 500);
  177. })
  178. .catch((error) => {
  179. console.error(error);
  180. toast.error("!ویرایش دسته با مشکل مواجه شد", {
  181. position: "top-right",
  182. autoClose: 1000,
  183. });
  184. })
  185. .finally(() => {
  186. loading.value = false;
  187. });
  188. };
  189. return {
  190. errors,
  191. loading,
  192. clearError,
  193. editCat,
  194. localTitle,
  195. iconData,
  196. setSelectedIcon,
  197. localIcon,
  198. localId,
  199. };
  200. },
  201. };
  202. </script>
  203. <style scoped>
  204. .modal-dialog {
  205. max-width: 50%;
  206. }
  207. .modal-content {
  208. padding: 1.5rem;
  209. }
  210. .modal-body {
  211. padding: 1rem 1.5rem;
  212. }
  213. .form-group {
  214. margin-bottom: 1.5rem;
  215. }
  216. .input-group {
  217. margin-top: 0.5rem;
  218. }
  219. .modal-header {
  220. border-bottom: 1px solid #dee2e6;
  221. padding-bottom: 1rem;
  222. }
  223. .Image-Preview {
  224. min-width: 100px;
  225. max-height: 100px;
  226. max-width: 100px;
  227. object-fit: cover;
  228. border-radius: 8px;
  229. border: 1px solid #ddd;
  230. }
  231. .selected-icon-container {
  232. display: flex;
  233. justify-content: center;
  234. align-items: center;
  235. margin-top: 10px;
  236. }
  237. .selected-icon-container i {
  238. font-size: 2.5rem;
  239. }
  240. .icon-container {
  241. display: flex;
  242. justify-content: center;
  243. align-items: center;
  244. margin: 8px;
  245. }
  246. .icon-container i {
  247. font-size: 2rem;
  248. margin-right: 10px;
  249. }
  250. .icon-item {
  251. display: inline-block;
  252. width: 33%;
  253. padding: 5px;
  254. text-align: center;
  255. }
  256. </style>