123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388 |
- <template>
- <SmartModal v-if="show" :title="$t('team.edit')" @close="hideModal">
- <template #body>
- <div class="flex flex-col px-2">
- <div class="flex relative">
- <input
- id="selectLabelTeamEdit"
- v-model="name"
- v-focus
- class="input floating-input"
- placeholder=" "
- type="text"
- autocomplete="off"
- @keyup.enter="saveTeam"
- />
- <label for="selectLabelTeamEdit">
- {{ $t("action.label") }}
- </label>
- </div>
- <div class="flex flex-1 justify-between items-center">
- <label for="memberList" class="p-4">
- {{ $t("team.members") }}
- </label>
- <div class="flex">
- <ButtonSecondary
- svg="plus"
- :label="$t('add.new')"
- @click.native="addTeamMember"
- />
- </div>
- </div>
- <div class="divide-y divide-dividerLight border-divider border rounded">
- <div
- v-for="(member, index) in members"
- :key="`member-${index}`"
- class="divide-x divide-dividerLight flex"
- >
- <input
- class="bg-transparent flex flex-1 py-2 px-4"
- :placeholder="$t('team.email')"
- :name="'param' + index"
- :value="member.user.email"
- readonly
- />
- <span>
- <tippy
- :ref="`memberOptions-${index}`"
- interactive
- trigger="click"
- theme="popover"
- arrow
- >
- <template #trigger>
- <span class="select-wrapper">
- <input
- class="
- bg-transparent
- cursor-pointer
- flex flex-1
- py-2
- px-4
- "
- :placeholder="$t('team.permissions')"
- :name="'value' + index"
- :value="
- typeof member.role === 'string'
- ? member.role
- : JSON.stringify(member.role)
- "
- readonly
- />
- </span>
- </template>
- <SmartItem
- label="OWNER"
- @click.native="updateMemberRole(index, 'OWNER')"
- />
- <SmartItem
- label="EDITOR"
- @click.native="updateMemberRole(index, 'EDITOR')"
- />
- <SmartItem
- label="VIEWER"
- @click.native="updateMemberRole(index, 'VIEWER')"
- />
- </tippy>
- </span>
- <div class="flex">
- <ButtonSecondary
- id="member"
- v-tippy="{ theme: 'tooltip' }"
- :title="$t('action.remove')"
- svg="trash"
- color="red"
- @click.native="removeExistingTeamMember(member.user.uid)"
- />
- </div>
- </div>
- <div
- v-for="(member, index) in newMembers"
- :key="`new-member-${index}`"
- class="divide-x divide-dividerLight flex"
- >
- <input
- v-model="member.key"
- class="bg-transparent flex flex-1 py-2 px-4"
- :placeholder="$t('team.email')"
- :name="'member' + index"
- autofocus
- />
- <span>
- <tippy
- :ref="`newMemberOptions-${index}`"
- interactive
- trigger="click"
- theme="popover"
- arrow
- >
- <template #trigger>
- <span class="select-wrapper">
- <input
- class="
- bg-transparent
- cursor-pointer
- flex flex-1
- py-2
- px-4
- "
- :placeholder="$t('team.permissions')"
- :name="'value' + index"
- :value="
- typeof member.value === 'string'
- ? member.value
- : JSON.stringify(member.value)
- "
- readonly
- />
- </span>
- </template>
- <SmartItem
- label="OWNER"
- @click.native="updateNewMemberRole(index, 'OWNER')"
- />
- <SmartItem
- label="EDITOR"
- @click.native="updateNewMemberRole(index, 'EDITOR')"
- />
- <SmartItem
- label="VIEWER"
- @click.native="updateNewMemberRole(index, 'VIEWER')"
- />
- </tippy>
- </span>
- <div class="flex">
- <ButtonSecondary
- id="member"
- v-tippy="{ theme: 'tooltip' }"
- :title="$t('action.remove')"
- svg="trash"
- color="red"
- @click.native="removeTeamMember(index)"
- />
- </div>
- </div>
- <div
- v-if="members.length === 0 && newMembers.length === 0"
- class="
- flex flex-col
- text-secondaryLight
- p-4
- items-center
- justify-center
- "
- >
- <SmartIcon class="opacity-75 pb-2" name="users" />
- <span class="text-center pb-4">
- {{ $t("empty.members") }}
- </span>
- <ButtonSecondary
- :label="$t('add.new')"
- filled
- @click.native="addTeamMember"
- />
- </div>
- </div>
- </div>
- </template>
- <template #footer>
- <span>
- <ButtonPrimary :label="$t('action.save')" @click.native="saveTeam" />
- <ButtonSecondary
- :label="$t('action.cancel')"
- @click.native="hideModal"
- />
- </span>
- </template>
- </SmartModal>
- </template>
- <script>
- import cloneDeep from "lodash/cloneDeep"
- import { defineComponent } from "@nuxtjs/composition-api"
- import * as teamUtils from "~/helpers/teams/utils"
- import TeamMemberAdapter from "~/helpers/teams/TeamMemberAdapter"
- export default defineComponent({
- props: {
- show: Boolean,
- editingTeam: { type: Object, default: () => {} },
- editingteamID: { type: String, default: null },
- },
- data() {
- return {
- rename: null,
- members: [],
- newMembers: [],
- membersAdapter: new TeamMemberAdapter(null),
- }
- },
- computed: {
- editingTeamCopy() {
- return this.editingTeam
- },
- name: {
- get() {
- return this.editingTeam.name
- },
- set(name) {
- this.rename = name
- },
- },
- },
- watch: {
- editingteamID(teamID) {
- this.membersAdapter.changeTeamID(teamID)
- },
- },
- mounted() {
- this.membersAdapter.members$.subscribe((list) => {
- this.members = cloneDeep(list)
- })
- },
- methods: {
- updateMemberRole(id, role) {
- this.members[id].role = role
- this.$refs[`memberOptions-${id}`][0].tippy().hide()
- },
- updateNewMemberRole(id, role) {
- this.newMembers[id].value = role
- this.$refs[`newMemberOptions-${id}`][0].tippy().hide()
- },
- addTeamMember() {
- const member = { key: "", value: "" }
- this.newMembers.push(member)
- },
- removeExistingTeamMember(userID) {
- teamUtils
- .removeTeamMember(this.$apollo, userID, this.editingteamID)
- .then(() => {
- this.$toast.success(this.$t("team.member_removed"), {
- icon: "done",
- })
- this.hideModal()
- })
- .catch((e) => {
- this.$toast.error(this.$t("error.something_went_wrong"), {
- icon: "error_outline",
- })
- console.error(e)
- })
- },
- removeTeamMember(index) {
- this.newMembers.splice(index, 1)
- },
- validateEmail(emailID) {
- if (
- /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/.test(
- emailID
- )
- ) {
- return true
- }
- return false
- },
- saveTeam() {
- if (
- this.$data.rename !== null &&
- this.$data.rename.replace(/\s/g, "").length < 6
- ) {
- this.$toast.error(this.$t("team.name_length_insufficient"), {
- icon: "error_outline",
- })
- return
- }
- let invalidEmail = false
- this.$data.newMembers.forEach((element) => {
- if (!this.validateEmail(element.key)) {
- this.$toast.error(this.$t("team.invalid_email_format"), {
- icon: "error_outline",
- })
- invalidEmail = true
- }
- })
- if (invalidEmail) return
- let invalidPermission = false
- this.$data.newMembers.forEach((element) => {
- if (!element.value) {
- this.$toast.error(this.$t("invalid_member_permission"), {
- icon: "error_outline",
- })
- invalidPermission = true
- }
- })
- if (invalidPermission) return
- this.$data.newMembers.forEach((element) => {
- // Call to the graphql mutation
- teamUtils
- .addTeamMemberByEmail(
- this.$apollo,
- element.value,
- element.key,
- this.editingteamID
- )
- .then(() => {
- this.$toast.success(this.$t("team.saved"), {
- icon: "done",
- })
- })
- .catch((e) => {
- this.$toast.error(e, {
- icon: "error_outline",
- })
- console.error(e)
- })
- })
- this.members.forEach((element) => {
- teamUtils
- .updateTeamMemberRole(
- this.$apollo,
- element.user.uid,
- element.role,
- this.editingteamID
- )
- .then(() => {
- this.$toast.success(this.$t("team.member_role_updated"), {
- icon: "done",
- })
- })
- .catch((e) => {
- this.$toast.error(e, {
- icon: "error_outline",
- })
- console.error(e)
- })
- })
- if (this.$data.rename !== null) {
- const newName =
- this.name === this.$data.rename ? this.name : this.$data.rename
- if (!/\S/.test(newName))
- return this.$toast.error(this.$t("empty.team_name"), {
- icon: "error_outline",
- })
- // Call to the graphql mutation
- if (this.name !== this.rename)
- teamUtils
- .renameTeam(this.$apollo, newName, this.editingteamID)
- .then(() => {
- this.$toast.success(this.$t("team.saved"), {
- icon: "done",
- })
- })
- .catch((e) => {
- this.$toast.error(this.$t("error.something_went_wrong"), {
- icon: "error_outline",
- })
- console.error(e)
- })
- }
- this.hideModal()
- },
- hideModal() {
- this.rename = null
- this.newMembers = []
- this.$emit("hide-modal")
- },
- },
- })
- </script>
|