main
vue 245 lines 6.37 KB
Raw
1 <template>
2 <div class="flex flex-col">
3 <n-collapse-transition :show="mode === 'view'">
4 <div class="flex min-h-80 grow flex-col justify-between gap-5">
5 <div class="grid-auto-fit-200 grid gap-2">
6 <CardKV v-for="ak of authKeys" :key="ak.key">
7 <template #key>
8 {{ ak.key }}
9 </template>
10 <template #value>
11 {{ ak.value || "-" }}
12 </template>
13 </CardKV>
14 </div>
15
16 <div class="flex items-center justify-end gap-3">
17 <n-button :loading="updating" :disabled="deleting" secondary @click.stop="switchMode('edit')">
18 <template #icon>
19 <Icon :name="EditIcon" />
20 </template>
21 Edit
22 </n-button>
23
24 <n-button type="error" :loading="deleting" secondary @click.stop="handleDelete">
25 <template #icon>
26 <Icon :name="DeleteIcon" />
27 </template>
28 Delete
29 </n-button>
30 </div>
31 </div>
32 </n-collapse-transition>
33 <n-collapse-transition :show="mode === 'edit'">
34 <n-spin v-model:show="updating" class="flex min-h-80" content-class="flex grow flex-col">
35 <div class="flex grow flex-col justify-between gap-5">
36 <n-form ref="form" :rules :label-width="80" :model>
37 <div class="flex flex-wrap gap-2">
38 <div v-for="(_, key) of model" :key class="min-w-72 grow">
39 <n-form-item :label="key" :path="key">
40 <n-input v-model:value="model[key]" :placeholder="`${key}...`" clearable />
41 </n-form-item>
42 </div>
43 </div>
44 </n-form>
45
46 <div class="flex items-center justify-between gap-3">
47 <n-button secondary @click="switchMode('view')">
48 <template #icon>
49 <Icon :name="BackIcon" />
50 </template>
51 Back
52 </n-button>
53
54 <div class="flex items-center justify-end gap-3">
55 <n-button :disabled="updating" @click="reset()">Reset</n-button>
56
57 <n-button :loading="updating" type="success" :disabled="!isValid" @click="validate()">
58 <template #icon>
59 <Icon :name="UpdateIcon" />
60 </template>
61 Submit
62 </n-button>
63 </div>
64 </div>
65 </div>
66 </n-spin>
67 </n-collapse-transition>
68 </div>
69 </template>
70
71 <script setup lang="ts">
72 import type { FormInst, FormRules, FormValidationError } from "naive-ui"
73 import type { IntegrationAuthKeyPairs, UpdateIntegrationPayload } from "@/api/endpoints/integrations"
74 import type { CustomerIntegration } from "@/types/integrations.d"
75 import _uniqBy from "lodash/uniqBy"
76 import { NButton, NCollapseTransition, NForm, NFormItem, NInput, NSpin, useDialog, useMessage } from "naive-ui"
77 import { computed, ref } from "vue"
78 import Api from "@/api"
79 import CardKV from "@/components/common/cards/CardKV.vue"
80 import Icon from "@/components/common/Icon.vue"
81 import { handleDeleteIntegration } from "./utils"
82
83 const props = defineProps<{
84 integration: CustomerIntegration
85 }>()
86
87 const emit = defineEmits<{
88 (e: "deleted"): void
89 (e: "updated", value: CustomerIntegration): void
90 }>()
91
92 const EditIcon = "uil:edit-alt"
93 const BackIcon = "carbon:arrow-left"
94 const DeleteIcon = "ph:trash"
95 const UpdateIcon = "carbon:save"
96 const integration = ref(props.integration)
97 const dialog = useDialog()
98 const message = useMessage()
99 const form = ref<FormInst | null>(null)
100 const model = ref<Record<string, string | null>>({})
101 const mode = ref<"view" | "edit">("view")
102 const deleting = ref<boolean>(false)
103 const updating = ref<boolean>(false)
104 const authKeys = ref(getAuthKeys(integration.value))
105
106 const rules = computed(() =>
107 authKeys.value.reduce((acc, cur) => {
108 acc[cur.key] = {
109 required: true,
110 message: `Please insert the ${cur.key}`,
111 trigger: ["input", "blur"]
112 }
113 return acc
114 }, {} as FormRules)
115 )
116
117 const isValid = computed(() => {
118 let valid = true
119
120 for (const field of Object.entries(model.value)) {
121 if (!field[1]) {
122 valid = false
123 }
124 }
125
126 return valid
127 })
128
129 function validate() {
130 if (!form.value) return
131
132 form.value.validate((errors?: Array<FormValidationError>) => {
133 if (!errors) {
134 updateIntegration()
135 } else {
136 message.warning("You must fill in the required fields correctly.")
137 return false
138 }
139 })
140 }
141
142 function getAuthKeys(integration: CustomerIntegration) {
143 const keys: { key: string; value: string }[] = []
144
145 for (const subscriptions of integration.integration_subscriptions) {
146 for (const ak of subscriptions.integration_auth_keys) {
147 keys.push({
148 key: ak.auth_key_name,
149 value: ak.auth_value
150 })
151 }
152 }
153
154 return _uniqBy(keys, "key")
155 }
156
157 function updateAuthKeys(integrationAuthKeys: IntegrationAuthKeyPairs[]) {
158 for (const subscriptions of integration.value.integration_subscriptions) {
159 for (const ak of subscriptions.integration_auth_keys) {
160 const ia = integrationAuthKeys.find(i => i.auth_key_name === ak.auth_key_name)
161 ak.auth_value = ia?.auth_value || ak.auth_value
162 }
163 }
164
165 authKeys.value = getAuthKeys(integration.value)
166
167 return integration.value
168 }
169
170 function switchMode(newMode: "view" | "edit") {
171 mode.value = newMode
172
173 if (newMode === "edit") {
174 model.value = authKeys.value.reduce(
175 (acc, cur) => {
176 acc[cur.key] = cur.value
177 return acc
178 },
179 {} as Record<string, string>
180 )
181 }
182 }
183
184 function reset() {
185 model.value = authKeys.value.reduce(
186 (acc, cur) => {
187 acc[cur.key] = null
188 return acc
189 },
190 {} as Record<string, string | null>
191 )
192 }
193
194 function handleDelete() {
195 handleDeleteIntegration({
196 integration: integration.value,
197 cbBefore: () => {
198 deleting.value = true
199 },
200 cbSuccess: () => {
201 emit("deleted")
202 },
203 cbAfter: () => {
204 deleting.value = false
205 },
206 message,
207 dialog
208 })
209 }
210
211 function updateIntegration() {
212 updating.value = true
213
214 const payload: UpdateIntegrationPayload = {
215 customer_code: integration.value.customer_code,
216 integration_name: integration.value.integration_service_name,
217 integration_auth_keys: Object.entries(model.value).map(([key, val]) => ({
218 auth_key_name: key,
219 auth_value: val || ""
220 }))
221 }
222
223 Api.integrations
224 .updateIntegration(payload)
225 .then(res => {
226 if (res.data?.success) {
227 message.success(res.data?.message || "Customer integration successfully updated")
228
229 if (res.data?.additional_info) {
230 message.info(res.data.additional_info, { duration: 0, closable: true })
231 }
232
233 emit("updated", updateAuthKeys(payload.integration_auth_keys))
234 } else {
235 message.warning(res.data?.message || "An error occurred. Please try again later.")
236 }
237 })
238 .catch(err => {
239 message.error(err.response?.data?.message || "An error occurred. Please try again later.")
240 })
241 .finally(() => {
242 updating.value = false
243 })
244 }
245 </script>