|
|
|
@ -11,6 +11,15 @@ const focusRef = ref<HTMLInputElement>()
|
|
|
|
|
const isDivFocused = ref(false) |
|
|
|
|
const divRef = ref<HTMLDivElement>() |
|
|
|
|
|
|
|
|
|
const emailValidation = reactive({ |
|
|
|
|
isError: false, |
|
|
|
|
message: '', |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
const validateEmail = (email: string): boolean => { |
|
|
|
|
const regEx = /^[^\s@]+@[^\s@]+\.[^\s@]+$/ |
|
|
|
|
return regEx.test(email) |
|
|
|
|
} |
|
|
|
|
const workspaceStore = useWorkspace() |
|
|
|
|
|
|
|
|
|
const { inviteCollaborator: _inviteCollaborator } = workspaceStore |
|
|
|
@ -24,25 +33,44 @@ watch(inviteData, (newVal) => {
|
|
|
|
|
emailBadges.value.push(newVal.email.split(',')[0]) |
|
|
|
|
inviteData.email = '' |
|
|
|
|
} |
|
|
|
|
if (newVal.email.length < 1 && emailValidation.isError) { |
|
|
|
|
emailValidation.isError = false |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
const scrollToEnd = () => { |
|
|
|
|
if (divRef.value) { |
|
|
|
|
const maxScrollLeft = divRef.value.scrollWidth - divRef.value.clientWidth |
|
|
|
|
divRef.value.scrollLeft = maxScrollLeft |
|
|
|
|
divRef.value.scrollLeft = divRef.value.scrollWidth |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const handleEnter = () => { |
|
|
|
|
if (inviteData.email.length < 1) { |
|
|
|
|
emailValidation.isError = true |
|
|
|
|
emailValidation.message = 'email should not be empty' |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
if (!validateEmail(inviteData.email)) { |
|
|
|
|
emailValidation.isError = true |
|
|
|
|
emailValidation.message = 'invalid emamil' |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
inviteData.email += ',' |
|
|
|
|
emailValidation.isError = false |
|
|
|
|
emailValidation.message = '' |
|
|
|
|
scrollToEnd() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const inviteCollaborator = async () => { |
|
|
|
|
try { |
|
|
|
|
let inviteEmails = '' |
|
|
|
|
emailBadges.value.forEach((el) => { |
|
|
|
|
inviteEmails += `${el},` |
|
|
|
|
emailBadges.value.forEach((el, index) => { |
|
|
|
|
// prevent the last email from getting the "," |
|
|
|
|
if (index === emailBadges.value.length - 1) { |
|
|
|
|
inviteEmails += el |
|
|
|
|
} else { |
|
|
|
|
inviteEmails += `${el},` |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
await _inviteCollaborator(inviteEmails, inviteData.roles) |
|
|
|
@ -74,37 +102,40 @@ onMounted(async () => {
|
|
|
|
|
<div class="my-2 pt-3 ml-2" data-testid="invite"> |
|
|
|
|
<div class="text-xl mb-4">Invite</div> |
|
|
|
|
<div class="flex gap-2"> |
|
|
|
|
<div |
|
|
|
|
ref="divRef" |
|
|
|
|
class="flex w-130 gap-1 overflow-x-scroll border-1 border-blue items-center rounded-lg nc-scrollbar-x-md overflow-hidden" |
|
|
|
|
tabindex="0" |
|
|
|
|
:class="{ |
|
|
|
|
'border-[#3366FF]': isDivFocused, |
|
|
|
|
}" |
|
|
|
|
@click=" |
|
|
|
|
() => { |
|
|
|
|
focusRef?.focus |
|
|
|
|
isDivFocused = true |
|
|
|
|
} |
|
|
|
|
" |
|
|
|
|
@blur="isDivFocused = false" |
|
|
|
|
> |
|
|
|
|
<span |
|
|
|
|
v-for="(email, index) in emailBadges" |
|
|
|
|
:key="email" |
|
|
|
|
class="text-[14px] p-0.2 border-1 color-[#4A5268] bg-[#E7E7E9] rounded-md flex items-center justify-between ml-1 mt-1" |
|
|
|
|
<div class="flex flex-col"> |
|
|
|
|
<div |
|
|
|
|
ref="divRef" |
|
|
|
|
class="flex w-130 gap-1 overflow-x-scroll border-1 border-blue items-center rounded-lg nc-scrollbar-x-md" |
|
|
|
|
tabindex="0" |
|
|
|
|
:class="{ |
|
|
|
|
'border-[#3366FF]': isDivFocused, |
|
|
|
|
}" |
|
|
|
|
@click=" |
|
|
|
|
() => { |
|
|
|
|
focusRef?.focus |
|
|
|
|
isDivFocused = true |
|
|
|
|
} |
|
|
|
|
" |
|
|
|
|
@blur="isDivFocused = false" |
|
|
|
|
> |
|
|
|
|
{{ email }} |
|
|
|
|
<component :is="iconMap.close" class="ml-1.5 hover:cursor-pointer" @click="emailBadges.splice(index, 1)" /> |
|
|
|
|
</span> |
|
|
|
|
<input |
|
|
|
|
id="email" |
|
|
|
|
ref="focusRef" |
|
|
|
|
v-model="inviteData.email" |
|
|
|
|
:placeholder="emailBadges.length < 1 ? 'Enter emails to send invitation' : ''" |
|
|
|
|
class="!border-none !focus:border-none !outline-0 !focus:outline-0 !bg-[white] ml-2 mr-3 w-full mt-1" |
|
|
|
|
@keyup.enter="handleEnter" |
|
|
|
|
/> |
|
|
|
|
<span |
|
|
|
|
v-for="(email, index) in emailBadges" |
|
|
|
|
:key="email" |
|
|
|
|
class="text-[14px] p-0.2 border-1 color-[#4A5268] bg-[#E7E7E9] rounded-md flex items-center justify-between ml-1 mt-1" |
|
|
|
|
> |
|
|
|
|
{{ email }} |
|
|
|
|
<component :is="iconMap.close" class="ml-1.5 hover:cursor-pointer" @click="emailBadges.splice(index, 1)" /> |
|
|
|
|
</span> |
|
|
|
|
<input |
|
|
|
|
id="email" |
|
|
|
|
ref="focusRef" |
|
|
|
|
v-model="inviteData.email" |
|
|
|
|
:placeholder="emailBadges.length < 1 ? 'Enter emails to send invitation' : ''" |
|
|
|
|
class="min-w-30 !focus:border-none !outline-0 !focus:outline-0 !bg-[white] ml-2 mr-3 w-full mt-1" |
|
|
|
|
@keyup.enter="handleEnter" |
|
|
|
|
/> |
|
|
|
|
</div> |
|
|
|
|
<span v-if="emailValidation.isError" class="ml-2 text-[red] text-[12px] mt-1">{{ emailValidation.message }}</span> |
|
|
|
|
</div> |
|
|
|
|
<NcSelect v-model:value="inviteData.roles" class="min-w-30 !rounded px-1" data-testid="roles"> |
|
|
|
|
<template #suffixIcon> |
|
|
|
@ -121,7 +152,7 @@ onMounted(async () => {
|
|
|
|
|
|
|
|
|
|
<NcButton |
|
|
|
|
type="primary" |
|
|
|
|
:disabled="!emailBadges.length || isInvitingCollaborators" |
|
|
|
|
:disabled="!emailBadges.length || isInvitingCollaborators || emailValidation.isError" |
|
|
|
|
size="small" |
|
|
|
|
@click="inviteCollaborator" |
|
|
|
|
> |
|
|
|
|