mirror of
https://github.com/abhinavxd/libredesk.git
synced 2025-11-01 20:44:12 +00:00
feat: translate /admin/users
This commit is contained in:
@@ -136,7 +136,7 @@
|
||||
{{
|
||||
holidayDate && !isNaN(new Date(holidayDate).getTime())
|
||||
? format(new Date(holidayDate), 'MMMM dd, yyyy')
|
||||
: t('form.field.pick_a_date')
|
||||
: t('form.field.pickDate')
|
||||
}}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>
|
||||
{{ t('admin.business_hours.delete_confirmation_title') }}
|
||||
{{ t('globals.messages.areYouAbsolutelySure') }}
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
{{ t('admin.business_hours.delete_confirmation') }}
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
<AlertDialog :open="alertOpen" @update:open="alertOpen = $event">
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>{{ $t('admin.inbox.delete_confirmation_title') }}</AlertDialogTitle>
|
||||
<AlertDialogTitle>{{ $t('globals.messages.areYouAbsolutelySure') }}</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
{{ $t('admin.inbox.delete_confirmation') }}
|
||||
</AlertDialogDescription>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<AlertDialog :open="isDeleteOpen" @update:open="isDeleteOpen = $event">
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>{{ $t('admin.macro.delete_confirmation_title') }}</AlertDialogTitle>
|
||||
<AlertDialogTitle>{{ $t('globals.messages.areYouAbsolutelySure') }}</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
{{ $t('admin.macro.delete_confirmation') }}
|
||||
</AlertDialogDescription>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<AlertDialog :open="alertOpen" @update:open="alertOpen = $event">
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>{{ t('admin.sla.delete_confirmation_title') }}</AlertDialogTitle>
|
||||
<AlertDialogTitle>{{ t('globals.messages.areYouAbsolutelySure') }}</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
{{ t('admin.sla.delete_confirmation') }}
|
||||
</AlertDialogDescription>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>
|
||||
{{ $t('admin.conversation_status.delete_confirmation_title') }}</AlertDialogTitle
|
||||
{{ $t('globals.messages.areYouAbsolutelySure') }}</AlertDialogTitle
|
||||
>
|
||||
<AlertDialogDescription>
|
||||
{{ $t('admin.conversation_status.delete_confirmation') }}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<AlertDialog :open="alertOpen" @update:open="alertOpen = $event">
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>{{t('admin.conversation_tags.delete_confirmation_title')}}</AlertDialogTitle>
|
||||
<AlertDialogTitle>{{t('globals.messages.areYouAbsolutelySure')}}</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
{{t('admin.conversation_tags.delete_confirmation')}}
|
||||
</AlertDialogDescription>
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
<form @submit.prevent="onSubmit" class="space-y-6">
|
||||
<FormField v-slot="{ field }" name="first_name">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>First name</FormLabel>
|
||||
<FormLabel>{{ $t('form.field.firstName') }}</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="text" placeholder="First name" v-bind="field" />
|
||||
<Input type="text" placeholder="" v-bind="field" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@@ -12,9 +12,9 @@
|
||||
|
||||
<FormField v-slot="{ field }" name="last_name">
|
||||
<FormItem>
|
||||
<FormLabel>Last name</FormLabel>
|
||||
<FormLabel>{{ $t('form.field.lastName') }}</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="text" placeholder="Last name" v-bind="field" />
|
||||
<Input type="text" placeholder="" v-bind="field" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@@ -22,19 +22,24 @@
|
||||
|
||||
<FormField v-slot="{ field }" name="email">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<FormLabel>{{ $t('form.field.email') }}</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="email" placeholder="Email" v-bind="field" />
|
||||
<Input type="email" placeholder="" v-bind="field" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<FormField v-slot="{ componentField , handleChange }" name="teams">
|
||||
<FormField v-slot="{ componentField, handleChange }" name="teams">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>Teams</FormLabel>
|
||||
<FormLabel>{{ $t('form.field.teams') }}</FormLabel>
|
||||
<FormControl>
|
||||
<SelectTag :items="teamOptions" placeholder="Select teams" v-model="componentField.modelValue" @update:modelValue="handleChange"/>
|
||||
<SelectTag
|
||||
:items="teamOptions"
|
||||
:placeholder="t('form.field.selectTeams')"
|
||||
v-model="componentField.modelValue"
|
||||
@update:modelValue="handleChange"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@@ -42,9 +47,14 @@
|
||||
|
||||
<FormField v-slot="{ componentField, handleChange }" name="roles">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>Roles</FormLabel>
|
||||
<FormLabel>{{ $t('form.field.roles') }}</FormLabel>
|
||||
<FormControl>
|
||||
<SelectTag :items="roleOptions" placeholder="Select roles" v-model="componentField.modelValue" @update:modelValue="handleChange"/>
|
||||
<SelectTag
|
||||
:items="roleOptions"
|
||||
:placeholder="t('form.field.selectRoles')"
|
||||
v-model="componentField.modelValue"
|
||||
@update:modelValue="handleChange"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@@ -52,9 +62,9 @@
|
||||
|
||||
<FormField v-slot="{ field }" name="new_password" v-if="!isNewForm">
|
||||
<FormItem v-auto-animate>
|
||||
<FormLabel>Set password</FormLabel>
|
||||
<FormLabel>{{ t('form.field.setPassword') }}</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="password" placeholder="Password" v-bind="field" />
|
||||
<Input type="password" placeholder="" v-bind="field" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@@ -65,7 +75,7 @@
|
||||
<FormControl>
|
||||
<div class="flex items-center space-x-2">
|
||||
<Checkbox :checked="value" @update:checked="handleChange" />
|
||||
<Label>Send welcome email?</Label>
|
||||
<Label>{{ $t('form.field.sendWelcomeEmail') }}</Label>
|
||||
</div>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
@@ -78,7 +88,7 @@
|
||||
<Checkbox :checked="value" @update:checked="handleChange" />
|
||||
</FormControl>
|
||||
<div class="space-y-1 leading-none">
|
||||
<FormLabel> Enabled </FormLabel>
|
||||
<FormLabel> {{ $t('form.field.enabled') }} </FormLabel>
|
||||
<FormMessage />
|
||||
</div>
|
||||
</FormItem>
|
||||
@@ -93,13 +103,14 @@ import { watch, onMounted, ref, computed } from 'vue'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { useForm } from 'vee-validate'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import { userFormSchema } from './formSchema.js'
|
||||
import { createFormSchema } from './formSchema.js'
|
||||
import { Checkbox } from '@/components/ui/checkbox'
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { vAutoAnimate } from '@formkit/auto-animate/vue'
|
||||
import { FormControl, FormField, FormItem, FormLabel, FormMessage } from '@/components/ui/form'
|
||||
import { SelectTag } from '@/components/ui/select'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import api from '@/api'
|
||||
|
||||
const props = defineProps({
|
||||
@@ -126,7 +137,7 @@ const props = defineProps({
|
||||
required: false
|
||||
}
|
||||
})
|
||||
|
||||
const { t } = useI18n()
|
||||
const teams = ref([])
|
||||
const roles = ref([])
|
||||
|
||||
@@ -140,11 +151,15 @@ onMounted(async () => {
|
||||
}
|
||||
})
|
||||
|
||||
const teamOptions = computed(() => teams.value.map((team) => ({ label: team.name, value: team.name })))
|
||||
const roleOptions = computed(() => roles.value.map((role) => ({ label: role.name, value: role.name })))
|
||||
const teamOptions = computed(() =>
|
||||
teams.value.map((team) => ({ label: team.name, value: team.name }))
|
||||
)
|
||||
const roleOptions = computed(() =>
|
||||
roles.value.map((role) => ({ label: role.name, value: role.name }))
|
||||
)
|
||||
|
||||
const form = useForm({
|
||||
validationSchema: toTypedSchema(userFormSchema)
|
||||
validationSchema: toTypedSchema(createFormSchema(t))
|
||||
})
|
||||
|
||||
const onSubmit = form.handleSubmit((values) => {
|
||||
|
||||
@@ -2,11 +2,11 @@ import { h } from 'vue'
|
||||
import UserDataTableDropDown from '@/features/admin/users/dataTableDropdown.vue'
|
||||
import { format } from 'date-fns'
|
||||
|
||||
export const columns = [
|
||||
export const createColumns = (t) => [
|
||||
{
|
||||
accessorKey: 'first_name',
|
||||
header: function () {
|
||||
return h('div', { class: 'text-center' }, 'First name')
|
||||
return h('div', { class: 'text-center' }, t('form.field.firstName'))
|
||||
},
|
||||
cell: function ({ row }) {
|
||||
return h('div', { class: 'text-center font-medium' }, row.getValue('first_name'))
|
||||
@@ -15,7 +15,7 @@ export const columns = [
|
||||
{
|
||||
accessorKey: 'last_name',
|
||||
header: function () {
|
||||
return h('div', { class: 'text-center' }, 'Last name')
|
||||
return h('div', { class: 'text-center' }, t('form.field.lastName'))
|
||||
},
|
||||
cell: function ({ row }) {
|
||||
return h('div', { class: 'text-center font-medium' }, row.getValue('last_name'))
|
||||
@@ -24,16 +24,16 @@ export const columns = [
|
||||
{
|
||||
accessorKey: 'enabled',
|
||||
header: function () {
|
||||
return h('div', { class: 'text-center' }, 'Enabled')
|
||||
return h('div', { class: 'text-center' }, t('form.field.enabled'))
|
||||
},
|
||||
cell: function ({ row }) {
|
||||
return h('div', { class: 'text-center font-medium' }, row.getValue('enabled') ? 'Yes' : 'No')
|
||||
return h('div', { class: 'text-center font-medium' }, row.getValue('enabled') ? t('globals.messages.yes') : t('globals.messages.no'))
|
||||
}
|
||||
},
|
||||
{
|
||||
accessorKey: 'email',
|
||||
header: function () {
|
||||
return h('div', { class: 'text-center' }, 'Email')
|
||||
return h('div', { class: 'text-center' }, t('form.field.email'))
|
||||
},
|
||||
cell: function ({ row }) {
|
||||
return h('div', { class: 'text-center font-medium' }, row.getValue('email'))
|
||||
@@ -42,7 +42,7 @@ export const columns = [
|
||||
{
|
||||
accessorKey: 'created_at',
|
||||
header: function () {
|
||||
return h('div', { class: 'text-center' }, 'Created at')
|
||||
return h('div', { class: 'text-center' }, t('form.field.createdAt'))
|
||||
},
|
||||
cell: function ({ row }) {
|
||||
return h(
|
||||
@@ -55,7 +55,7 @@ export const columns = [
|
||||
{
|
||||
accessorKey: 'updated_at',
|
||||
header: function () {
|
||||
return h('div', { class: 'text-center' }, 'Updated at')
|
||||
return h('div', { class: 'text-center' }, t('form.field.updatedAt'))
|
||||
},
|
||||
cell: function ({ row }) {
|
||||
return h(
|
||||
|
||||
@@ -2,27 +2,31 @@
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<Button variant="ghost" class="w-8 h-8 p-0">
|
||||
<span class="sr-only">Open menu</span>
|
||||
<span class="sr-only"></span>
|
||||
<MoreHorizontal class="w-4 h-4" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<DropdownMenuItem @click="editUser(props.user.id)">Edit</DropdownMenuItem>
|
||||
<DropdownMenuItem @click="() => (alertOpen = true)">Delete</DropdownMenuItem>
|
||||
<DropdownMenuItem @click="editUser(props.user.id)">{{
|
||||
$t('globals.buttons.edit')
|
||||
}}</DropdownMenuItem>
|
||||
<DropdownMenuItem @click="() => (alertOpen = true)">{{
|
||||
$t('globals.buttons.delete')
|
||||
}}</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
<AlertDialog :open="alertOpen" @update:open="alertOpen = $event">
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Delete User</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
This action cannot be undone. This will permanently delete the user.
|
||||
</AlertDialogDescription>
|
||||
<AlertDialogTitle>{{ $t('globals.messages.areYouAbsolutelySure') }}</AlertDialogTitle>
|
||||
<AlertDialogDescription>{{ $t('admin.user.deleteConfirmation') }}</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction @click="handleDelete">Delete</AlertDialogAction>
|
||||
<AlertDialogCancel>{{ $t('globals.buttons.cancel') }}</AlertDialogCancel>
|
||||
<AlertDialogAction @click="handleDelete">{{
|
||||
$t('globals.buttons.delete')
|
||||
}}</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
@@ -79,7 +83,6 @@ async function handleDelete() {
|
||||
emitRefreshUserList()
|
||||
} catch (error) {
|
||||
emit.emit(EMITTER_EVENTS.SHOW_TOAST, {
|
||||
title: 'Error',
|
||||
variant: 'destructive',
|
||||
description: handleHTTPError(error).message
|
||||
})
|
||||
|
||||
@@ -1,34 +1,48 @@
|
||||
import * as z from 'zod'
|
||||
|
||||
export const userFormSchema = z.object({
|
||||
export const createFormSchema = (t) => z.object({
|
||||
first_name: z
|
||||
.string({
|
||||
required_error: 'First name is required.'
|
||||
required_error: t('globals.messages.required'),
|
||||
})
|
||||
.min(2, {
|
||||
message: 'First name must be at least 2 characters.'
|
||||
message: t('form.error.minmax', {
|
||||
min: 2,
|
||||
max: 50,
|
||||
})
|
||||
})
|
||||
.max(50, {
|
||||
message: t('form.error.minmax', {
|
||||
min: 2,
|
||||
max: 50,
|
||||
})
|
||||
}),
|
||||
|
||||
last_name: z.string().optional(),
|
||||
|
||||
email: z
|
||||
.string({
|
||||
required_error: 'Email is required.'
|
||||
required_error: t('globals.messages.required'),
|
||||
})
|
||||
.email({
|
||||
message: 'Invalid email address.'
|
||||
message: t('globals.messages.invalidEmailAddress'),
|
||||
}),
|
||||
|
||||
send_welcome_email: z.boolean().optional(),
|
||||
|
||||
teams: z.array(z.string()).default([]),
|
||||
|
||||
roles: z.array(z.string()).min(1, 'Please select at least one role.'),
|
||||
roles: z.array(z.string()).min(1, t('globals.messages.pleaseSelectAtLeastOne', {
|
||||
name: t('globals.entities.role')
|
||||
})),
|
||||
|
||||
new_password: z
|
||||
.string()
|
||||
.regex(/^$|^(?=.*[A-Z])(?=.*\d)[A-Za-z\d]{8,50}$/, {
|
||||
message: 'Password must be between 8 and 50 characters long, contain at least one uppercase letter and one number.'
|
||||
.regex(/^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[\W_]).{10,72}$/, {
|
||||
message: t('globals.messages.strongPassword', {
|
||||
min: 10,
|
||||
max: 72,
|
||||
})
|
||||
})
|
||||
.optional(),
|
||||
enabled: z.boolean().optional().default(true)
|
||||
|
||||
@@ -13,14 +13,21 @@ import { CustomBreadcrumb } from '@/components/ui/breadcrumb'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useEmitter } from '@/composables/useEmitter'
|
||||
import { EMITTER_EVENTS } from '@/constants/emitterEvents.js'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import api from '@/api'
|
||||
|
||||
const { t } = useI18n()
|
||||
const emitter = useEmitter()
|
||||
const router = useRouter()
|
||||
const formLoading = ref(false)
|
||||
const breadcrumbLinks = [
|
||||
{ path: 'user-list', label: 'Users' },
|
||||
{ path: '', label: 'Add user' }
|
||||
{ path: 'user-list', label: t('globals.entities.user', 2) },
|
||||
{
|
||||
path: '',
|
||||
label: t('globals.messages.new', {
|
||||
name: t('globals.entities.user', 1)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
const onSubmit = (values) => {
|
||||
@@ -32,13 +39,13 @@ const createNewUser = async (values) => {
|
||||
formLoading.value = true
|
||||
await api.createUser(values)
|
||||
emitter.emit(EMITTER_EVENTS.SHOW_TOAST, {
|
||||
title: 'Success',
|
||||
description: 'User created successfully'
|
||||
description: t('globals.messages.createdSuccessfully', {
|
||||
name: t('globals.entities.user', 1)
|
||||
})
|
||||
})
|
||||
router.push({ name: 'user-list' })
|
||||
} catch (error) {
|
||||
emitter.emit(EMITTER_EVENTS.SHOW_TOAST, {
|
||||
title: 'Error',
|
||||
variant: 'destructive',
|
||||
description: handleHTTPError(error).message
|
||||
})
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="mb-5">
|
||||
<CustomBreadcrumb :links="breadcrumbLinks" />
|
||||
</div>
|
||||
<Spinner v-if="isLoading"></Spinner>
|
||||
<Spinner v-if="isLoading"/>
|
||||
<UserForm :initialValues="user" :submitForm="submitForm" :isLoading="formLoading" v-else />
|
||||
</template>
|
||||
|
||||
@@ -15,15 +15,22 @@ import { handleHTTPError } from '@/utils/http'
|
||||
import UserForm from '@/features/admin/users/UserForm.vue'
|
||||
import { CustomBreadcrumb } from '@/components/ui/breadcrumb'
|
||||
import { Spinner } from '@/components/ui/spinner'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const user = ref({})
|
||||
const { t } = useI18n()
|
||||
const isLoading = ref(false)
|
||||
const formLoading = ref(false)
|
||||
const emitter = useEmitter()
|
||||
|
||||
const breadcrumbLinks = [
|
||||
{ path: 'user-list', label: 'Users' },
|
||||
{ path: '', label: 'Edit user' }
|
||||
{ path: 'user-list', label: t('globals.entities.user', 2) },
|
||||
{
|
||||
path: '',
|
||||
label: t('globals.messages.edit', {
|
||||
name: t('globals.entities.user', 1)
|
||||
})
|
||||
}
|
||||
]
|
||||
|
||||
const submitForm = (values) => {
|
||||
@@ -35,12 +42,12 @@ const updateUser = async (payload) => {
|
||||
formLoading.value = true
|
||||
await api.updateUser(user.value.id, payload)
|
||||
emitter.emit(EMITTER_EVENTS.SHOW_TOAST, {
|
||||
title: "Success",
|
||||
description: "User updated successfully"
|
||||
description: t('globals.messages.updatedSuccessfully', {
|
||||
name: t('globals.entities.user', 1)
|
||||
})
|
||||
})
|
||||
} catch (error) {
|
||||
emitter.emit(EMITTER_EVENTS.SHOW_TOAST, {
|
||||
title: 'Error',
|
||||
variant: 'destructive',
|
||||
description: handleHTTPError(error).message
|
||||
})
|
||||
@@ -56,7 +63,6 @@ onMounted(async () => {
|
||||
user.value = resp.data.data
|
||||
} catch (error) {
|
||||
emitter.emit(EMITTER_EVENTS.SHOW_TOAST, {
|
||||
title: 'Error',
|
||||
variant: 'destructive',
|
||||
description: handleHTTPError(error).message
|
||||
})
|
||||
|
||||
@@ -3,18 +3,22 @@
|
||||
<div :class="{ 'transition-opacity duration-300 opacity-50': isLoading }">
|
||||
<div class="flex justify-end mb-5">
|
||||
<router-link :to="{ name: 'new-user' }">
|
||||
<Button>New User</Button>
|
||||
<Button>{{
|
||||
$t('globals.messages.new', {
|
||||
name: $t('globals.entities.user', 1)
|
||||
})
|
||||
}}</Button>
|
||||
</router-link>
|
||||
</div>
|
||||
<div>
|
||||
<DataTable :columns="columns" :data="data" />
|
||||
<DataTable :columns="createColumns(t)" :data="data" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { onMounted, ref } from 'vue'
|
||||
import { columns } from '@/features/admin/users/dataTableColumns.js'
|
||||
import { createColumns } from '@/features/admin/users/dataTableColumns.js'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import DataTable from '@/components/datatable/DataTable.vue'
|
||||
import { handleHTTPError } from '@/utils/http'
|
||||
@@ -22,8 +26,10 @@ import { Spinner } from '@/components/ui/spinner'
|
||||
import { useEmitter } from '@/composables/useEmitter'
|
||||
import { EMITTER_EVENTS } from '@/constants/emitterEvents.js'
|
||||
import api from '@/api'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
|
||||
const isLoading = ref(false)
|
||||
const { t } = useI18n()
|
||||
const data = ref([])
|
||||
const emitter = useEmitter()
|
||||
|
||||
@@ -41,7 +47,6 @@ const getData = async () => {
|
||||
data.value = response.data.data
|
||||
} catch (error) {
|
||||
emitter.emit(EMITTER_EVENTS.SHOW_TOAST, {
|
||||
title: 'Error',
|
||||
variant: 'destructive',
|
||||
description: handleHTTPError(error).message
|
||||
})
|
||||
|
||||
27
i18n/en.json
27
i18n/en.json
@@ -67,13 +67,22 @@
|
||||
"globals.messages.errorSending": "Error sending {name}",
|
||||
"globals.messages.errorAlreadyExists": "{name} already exists",
|
||||
"globals.messages.errorMarshallingMeta": "Error marshalling meta",
|
||||
"globals.messages.areYouAbsolutelySure": "Are you absolutely sure?",
|
||||
"globals.messages.errorMarshalling": "Error marshalling",
|
||||
"globals.messages.errorSearching": "Error searching {name}",
|
||||
"globals.messages.tooLong": "{name} is too long, should be at most {max} characters",
|
||||
"globals.messages.deletedSuccessfully": "{name} deleted successfully",
|
||||
"globals.messages.updatedSuccessfully": "{name} updated successfully",
|
||||
"globals.messages.edit": "Edit {name}",
|
||||
"globals.messages.delete": "Delete {name}",
|
||||
"globals.messages.create": "Create {name}",
|
||||
"globals.messages.new": "New {name}",
|
||||
"globals.messages.yes": "Yes",
|
||||
"globals.messages.no": "No",
|
||||
"globals.messages.createdSuccessfully": "{name} created successfully",
|
||||
"globals.messages.invalidEmailAddress": "Invalid email address",
|
||||
"globals.messages.pleaseSelectAtLeastOne": "Please select at least one {name}",
|
||||
"globals.messages.strongPassword": "Password must be between {min} and {max} characters long, contain at least one uppercase letter and one number.",
|
||||
"globals.messages.noResultsFound": "No results found",
|
||||
"globals.messages.couldNotReload": "Could not reload {name}. Please restart the app",
|
||||
"globals.messages.invalid": "Invalid {name}",
|
||||
@@ -210,14 +219,22 @@
|
||||
"form.field.disabled": "Disabled",
|
||||
"form.field.port": "Port",
|
||||
"form.field.host": "Host",
|
||||
"form.field.firstName": "First Name",
|
||||
"form.field.lastName": "Last Name",
|
||||
"form.field.teams": "Teams",
|
||||
"form.field.roles": "Roles",
|
||||
"form.field.setPassword": "Set Password",
|
||||
"form.field.sendWelcomeEmail": "Send Welcome Email?",
|
||||
"form.field.username": "Username",
|
||||
"form.field.password": "Password",
|
||||
"form.field.visibility": "Visibility",
|
||||
"form.field.usage": "Usage",
|
||||
"form.field.createdAt": "Created At",
|
||||
"form.field.updatedAt": "Updated At",
|
||||
"form.field.pick_a_date": "Pick a date",
|
||||
"form.field.pickDate": "Pick a date",
|
||||
"form.field.selectTLS": "Select TLS",
|
||||
"form.field.selectRoles": "Select roles",
|
||||
"form.field.selectTeams": "Select teams",
|
||||
"form.error.min": "Should be at least {min} characters",
|
||||
"form.error.max": "Should be at most {max} characters",
|
||||
"form.error.minmax": "Should be between {min} and {max} characters",
|
||||
@@ -257,7 +274,6 @@
|
||||
"admin.general.allowed_file_upload_extensions.description": "Allowed file upload extensions. Use `*` to allow all file types.",
|
||||
"admin.business_hours": "Business Hours",
|
||||
"admin.business_hours.delete": "Delete Business Hour",
|
||||
"admin.business_hours.delete_confirmation_title": "Are you sure?",
|
||||
"admin.business_hours.delete_confirmation": "This action cannot be undone. This will permanently delete this business hour.",
|
||||
"admin.business_hours.new": "New Business Hour",
|
||||
"admin.business_hours.new_holiday": "New Holiday",
|
||||
@@ -274,7 +290,6 @@
|
||||
"admin.sla.updated": "SLA Policy updated successfully",
|
||||
"admin.sla.created": "SLA Policy created successfully",
|
||||
"admin.sla.delete": "Delete SLA Policy",
|
||||
"admin.sla.delete_confirmation_title": "Are you sure?",
|
||||
"admin.sla.delete_confirmation": "This action cannot be undone. This will permanently delete this SLA policy.",
|
||||
"admin.sla.name.valid": "SLA Policy name should be between 1 and 255 characters",
|
||||
"admin.sla.description.valid": "SLA Policy description should be between 1 and 255 characters",
|
||||
@@ -306,7 +321,6 @@
|
||||
"admin.conversation_tags.updated": "Tag updated successfully",
|
||||
"admin.conversation_tags.created": "Tag created successfully",
|
||||
"admin.conversation_tags.name.valid": "Tag name should at least 3 characters",
|
||||
"admin.conversation_tags.delete_confirmation_title": "Are you absolutely sure?",
|
||||
"admin.conversation_tags.delete_confirmation": "This action cannot be undone. This will permanently delete this tag, and remove it from all conversations.",
|
||||
"admin.macro.message_content": "Response to be sent when macro is used (optional)",
|
||||
"admin.macro.message_content.placeholder": "Shift + Enter to add a new line",
|
||||
@@ -324,7 +338,6 @@
|
||||
"admin.macro.actionTypeRequired": "Action type is required",
|
||||
"admin.macro.actionValueRequired": "Action value is required",
|
||||
"admin.macro.teamOrUserRequired": "team is required when visibility is `team` & a user is required when visibility is `user`",
|
||||
"admin.macro.delete_confirmation_title": "Are you absolutely sure?",
|
||||
"admin.macro.delete_confirmation": "This action cannot be undone. This will permanently delete this macro.",
|
||||
"admin.macro.created": "Macro created successfully",
|
||||
"admin.macro": "Macros",
|
||||
@@ -336,7 +349,6 @@
|
||||
"admin.conversation_status.name.description": "Set status name. Click save when you're done.",
|
||||
"admin.conversation_status.updated": "Status updated successfully",
|
||||
"admin.conversation_status.created": "Status created successfully",
|
||||
"admin.conversation_status.delete_confirmation_title": "Are you absolutely sure?",
|
||||
"admin.conversation_status.delete_confirmation": "This action cannot be undone. This will permanently delete this status.",
|
||||
"admin.inbox.name.description": "Name for your inbox.",
|
||||
"admin.inbox.from_email_address.placeholder": "My inbox <support{'@'}example.com>",
|
||||
@@ -370,7 +382,6 @@
|
||||
"admin.inbox.helo_hostname.description": "The hostname to use in the HELO/EHLO command. If not set, defaults to localhost.",
|
||||
"admin.inbox.skipTLSVerification": "Skip TLS Verification",
|
||||
"admin.inbox.skipTLSVerification.description": "Skip hostname check on the TLS certificate.",
|
||||
"admin.inbox.delete_confirmation_title": "Are you absolutely sure?",
|
||||
"admin.inbox.delete_confirmation": "This action cannot be undone. This will permanently delete this inbox.",
|
||||
"admin.inbox.updated": "Inbox updated successfully",
|
||||
"admin.inbox.created": "Inbox created successfully",
|
||||
@@ -382,6 +393,8 @@
|
||||
"admin.inbox.configureChannel": "Configure channel",
|
||||
"admin.inbox.email": "Email",
|
||||
"admin.inbox.createEmailInbox": "Create Email Inbox",
|
||||
"admin.user.deleteConfirmation": "This action cannot be undone. This will permanently delete this user.",
|
||||
"admin.user.new": "New user",
|
||||
"globals.buttons.save": "Save",
|
||||
"globals.buttons.save_changes": "Save changes",
|
||||
"globals.buttons.cancel": "Cancel",
|
||||
|
||||
@@ -16,23 +16,23 @@ var (
|
||||
)
|
||||
|
||||
type User struct {
|
||||
ID int `db:"id" json:"id,omitempty"`
|
||||
ID int `db:"id" json:"id"`
|
||||
CreatedAt time.Time `db:"created_at" json:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
|
||||
FirstName string `db:"first_name" json:"first_name"`
|
||||
LastName string `db:"last_name" json:"last_name"`
|
||||
Email null.String `db:"email" json:"email,omitempty"`
|
||||
Email null.String `db:"email" json:"email"`
|
||||
Type string `db:"type" json:"type"`
|
||||
AvailabilityStatus string `db:"availability_status" json:"availability_status"`
|
||||
PhoneNumber null.String `db:"phone_number" json:"phone_number,omitempty"`
|
||||
PhoneNumber null.String `db:"phone_number" json:"phone_number"`
|
||||
AvatarURL null.String `db:"avatar_url" json:"avatar_url"`
|
||||
Enabled bool `db:"enabled" json:"enabled"`
|
||||
Password string `db:"password" json:"-"`
|
||||
Roles pq.StringArray `db:"roles" json:"roles,omitempty"`
|
||||
Permissions pq.StringArray `db:"permissions" json:"permissions,omitempty"`
|
||||
Meta pq.StringArray `db:"meta" json:"meta,omitempty"`
|
||||
CustomAttributes pq.StringArray `db:"custom_attributes" json:"custom_attributes,omitempty"`
|
||||
Teams tmodels.Teams `db:"teams" json:"teams,omitempty"`
|
||||
Roles pq.StringArray `db:"roles" json:"roles"`
|
||||
Permissions pq.StringArray `db:"permissions" json:"permissions"`
|
||||
Meta pq.StringArray `db:"meta" json:"meta"`
|
||||
CustomAttributes pq.StringArray `db:"custom_attributes" json:"custom_attributes"`
|
||||
Teams tmodels.Teams `db:"teams" json:"teams"`
|
||||
ContactChannelID int `db:"contact_channel_id" json:"contact_channel_id,omitempty"`
|
||||
NewPassword string `db:"-" json:"new_password,omitempty"`
|
||||
SendWelcomeEmail bool `db:"-" json:"send_welcome_email,omitempty"`
|
||||
|
||||
Reference in New Issue
Block a user