123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960 |
- <template>
- <div>
- <div class="flex flex-wrap flex-row items-center justify-between mb-8 md:px-2 lg:px-6">
- <div
- class="w-full md:w-1/2 lg:w-1/3 xl:w-1/6 md:-mx-2 lg:-mx-6 rounded overflow-hidden shadow-md bg-white mb-4 lg:mb-4 xl:mb-0"
- >
- <div class="p-4 flex items-center justify-between relative">
- <icon
- name="check-circle"
- class="inline-block w-16 h-16 text-indigo-50 stroke-current absolute top-0 right-0"
- />
- <div class="font-bold text-xl md:text-3xl text-indigo-800">
- {{ totalActive }}
- <p class="text-grey-200 text-sm tracking-wide uppercase">
- Active
- </p>
- </div>
- </div>
- </div>
- <div
- class="w-full md:w-1/2 lg:w-1/3 xl:w-1/6 md:-mx-2 lg:-mx-6 rounded overflow-hidden shadow-md bg-white mb-4 lg:mb-4 xl:mb-0"
- >
- <div class="p-4 flex items-center justify-between relative">
- <icon
- name="cross-circle"
- class="inline-block w-16 h-16 text-indigo-50 stroke-current absolute top-0 right-0"
- />
- <div class="font-bold text-xl md:text-3xl text-indigo-800">
- {{ totalInactive }}
- <p class="text-grey-200 text-sm tracking-wide uppercase">
- Inactive
- </p>
- </div>
- </div>
- </div>
- <div
- class="w-full md:w-1/2 lg:w-1/3 xl:w-1/6 md:-mx-2 lg:-mx-6 rounded overflow-hidden shadow-md bg-white mb-4 lg:mb-4 xl:mb-0"
- >
- <div class="p-4 flex items-center justify-between relative">
- <icon
- name="send"
- class="inline-block w-16 h-16 text-indigo-50 stroke-current absolute top-0 right-0"
- />
- <div class="font-bold text-xl md:text-3xl text-indigo-800">
- {{ totalForwarded }}
- <p class="text-grey-200 text-sm tracking-wide uppercase">
- Emails Forwarded
- </p>
- </div>
- </div>
- </div>
- <div
- class="w-full md:w-1/2 lg:w-1/3 xl:w-1/6 md:-mx-2 lg:-mx-6 rounded overflow-hidden shadow-md bg-white mb-4 lg:mb-0"
- >
- <div class="p-4 flex items-center justify-between relative">
- <icon
- name="blocked"
- class="inline-block w-16 h-16 text-indigo-50 stroke-current absolute top-0 right-0"
- />
- <div class="font-bold text-xl md:text-3xl text-indigo-800">
- {{ totalBlocked }}
- <p class="text-grey-200 text-sm tracking-wide uppercase">
- Emails Blocked
- </p>
- </div>
- </div>
- </div>
- <div
- class="w-full md:w-1/2 lg:w-1/3 xl:w-1/6 md:-mx-2 lg:-mx-6 rounded overflow-hidden shadow-md bg-white mb-4 md:mb-0"
- >
- <div class="p-4 flex items-center justify-between relative">
- <icon
- name="corner-up-left"
- class="inline-block w-16 h-16 text-indigo-50 stroke-current absolute top-0 right-0"
- />
- <div class="font-bold text-xl md:text-3xl text-indigo-800">
- {{ totalReplies }}
- <p class="text-grey-200 text-sm tracking-wide uppercase">
- Email Replies
- </p>
- </div>
- </div>
- </div>
- <div
- class="w-full md:w-1/2 lg:w-1/3 xl:w-1/6 md:-mx-2 lg:-mx-6 rounded overflow-hidden shadow-md bg-white"
- >
- <div class="p-4 flex items-center justify-between relative">
- <icon
- name="inbox"
- class="inline-block w-16 h-16 text-indigo-50 stroke-current absolute top-0 right-0"
- />
- <div class="font-bold text-xl md:text-3xl text-indigo-800">
- {{ bandwidthMb }}<span class="text-sm tracking-wide uppercase">MB</span>
- <p class="text-grey-200 text-sm tracking-wide uppercase">Bandwidth ({{ month }})</p>
- </div>
- </div>
- </div>
- </div>
- <div class="mb-6 flex flex-col md:flex-row justify-between md:items-center">
- <div class="relative">
- <input
- v-model="search"
- @keyup.esc="search = ''"
- tabindex="0"
- type="text"
- class="w-full md:w-64 appearance-none shadow bg-white text-grey-700 focus:outline-none rounded py-3 pl-3 pr-8"
- placeholder="Search Aliases"
- />
- <icon
- v-if="search"
- @click.native="search = ''"
- name="close-circle"
- class="absolute right-0 inset-y-0 w-5 h-full text-grey-300 fill-current mr-2 flex items-center cursor-pointer"
- />
- <icon
- v-else
- name="search"
- class="absolute right-0 inset-y-0 w-5 h-full text-grey-300 fill-current pointer-events-none mr-2 flex items-center"
- />
- </div>
- <div class="mt-4 md:mt-0">
- <button
- @click="generateAliasModalOpen = true"
- class="bg-cyan-400 hover:bg-cyan-300 text-cyan-900 font-bold py-3 px-4 rounded focus:outline-none ml-auto"
- >
- Generate New Alias
- </button>
- </div>
- </div>
- <div class="bg-white rounded shadow overflow-x-auto">
- <table v-if="initialAliases.length" class="w-full whitespace-no-wrap">
- <tr class="text-left font-semibold text-grey-500 text-sm tracking-wider">
- <th class="pl-4 pr-2 py-4">
- <div class="flex items-center">
- Created
- <div class="inline-flex flex-col">
- <icon
- name="chevron-up"
- @click.native="sort('created_at', 'asc')"
- class="w-4 h-4 text-grey-300 fill-current cursor-pointer"
- :class="{ 'text-grey-800': isCurrentSort('created_at', 'asc') }"
- />
- <icon
- name="chevron-down"
- @click.native="sort('created_at', 'desc')"
- class="w-4 h-4 text-grey-300 fill-current cursor-pointer"
- :class="{
- 'text-grey-800': isCurrentSort('created_at', 'desc'),
- }"
- />
- </div>
- </div>
- </th>
- <th class="px-2 py-4">
- <div class="flex items-center">
- Alias
- <div class="inline-flex flex-col">
- <icon
- name="chevron-up"
- @click.native="sort('email', 'asc')"
- class="w-4 h-4 text-grey-300 fill-current cursor-pointer"
- :class="{ 'text-grey-800': isCurrentSort('email', 'asc') }"
- />
- <icon
- name="chevron-down"
- @click.native="sort('email', 'desc')"
- class="w-4 h-4 text-grey-300 fill-current cursor-pointer"
- :class="{ 'text-grey-800': isCurrentSort('email', 'desc') }"
- />
- </div>
- </div>
- </th>
- <th class="px-2 py-4">
- <div class="flex items-center">
- Recipients
- <div class="inline-flex flex-col">
- <icon
- name="chevron-up"
- @click.native="sort('recipients', 'asc')"
- class="w-4 h-4 text-grey-300 fill-current cursor-pointer"
- :class="{ 'text-grey-800': isCurrentSort('recipients', 'asc') }"
- />
- <icon
- name="chevron-down"
- @click.native="sort('recipients', 'desc')"
- class="w-4 h-4 text-grey-300 fill-current cursor-pointer"
- :class="{ 'text-grey-800': isCurrentSort('recipients', 'desc') }"
- />
- </div>
- </div>
- </th>
- <th class="px-2 py-4">
- <div class="flex items-center">
- Description
- </div>
- </th>
- <th class="px-2 py-4">
- <div class="flex items-center">
- Forwarded
- <div class="inline-flex flex-col">
- <icon
- name="chevron-up"
- @click.native="sort('emails_forwarded', 'asc')"
- class="w-4 h-4 text-grey-300 fill-current cursor-pointer"
- :class="{
- 'text-grey-800': isCurrentSort('emails_forwarded', 'asc'),
- }"
- />
- <icon
- name="chevron-down"
- @click.native="sort('emails_forwarded', 'desc')"
- class="w-4 h-4 text-grey-300 fill-current cursor-pointer"
- :class="{
- 'text-grey-800': isCurrentSort('emails_forwarded', 'desc'),
- }"
- />
- </div>
- </div>
- </th>
- <th class="px-2 py-4 items-center">
- <div class="flex items-center">
- Blocked
- <div class="inline-flex flex-col">
- <icon
- name="chevron-up"
- @click.native="sort('emails_blocked', 'asc')"
- class="w-4 h-4 text-grey-300 fill-current cursor-pointer"
- :class="{
- 'text-grey-800': isCurrentSort('emails_blocked', 'asc'),
- }"
- />
- <icon
- name="chevron-down"
- @click.native="sort('emails_blocked', 'desc')"
- class="w-4 h-4 text-grey-300 fill-current cursor-pointer"
- :class="{
- 'text-grey-800': isCurrentSort('emails_blocked', 'desc'),
- }"
- />
- </div>
- </div>
- </th>
- <th class="px-2 py-4 items-center">
- <div class="flex items-center">
- Replies
- <div class="inline-flex flex-col">
- <icon
- name="chevron-up"
- @click.native="sort('emails_replied', 'asc')"
- class="w-4 h-4 text-grey-300 fill-current cursor-pointer"
- :class="{
- 'text-grey-800': isCurrentSort('emails_replied', 'asc'),
- }"
- />
- <icon
- name="chevron-down"
- @click.native="sort('emails_replied', 'desc')"
- class="w-4 h-4 text-grey-300 fill-current cursor-pointer"
- :class="{
- 'text-grey-800': isCurrentSort('emails_replied', 'desc'),
- }"
- />
- </div>
- </div>
- </th>
- <th class="px-2 py-4 items-center" colspan="2">
- <div class="flex items-center">
- Active
- <div class="inline-flex flex-col">
- <icon
- name="chevron-up"
- @click.native="sort('active', 'asc')"
- class="w-4 h-4 text-grey-300 fill-current cursor-pointer"
- :class="{ 'text-grey-800': isCurrentSort('active', 'asc') }"
- />
- <icon
- name="chevron-down"
- @click.native="sort('active', 'desc')"
- class="w-4 h-4 text-grey-300 fill-current cursor-pointer"
- :class="{ 'text-grey-800': isCurrentSort('active', 'desc') }"
- />
- </div>
- </div>
- </th>
- </tr>
- <tr
- v-for="alias in queriedAliases"
- :key="alias.id"
- class="hover:bg-grey-50 focus-within:bg-grey-50 h-20"
- >
- <td class="border-grey-200 border-t">
- <div class="pl-4 pr-2 py-4 flex items-center">
- <span
- class="tooltip outline-none text-sm"
- :data-tippy-content="alias.created_at | formatDate"
- >{{ alias.created_at | timeAgo }}</span
- >
- </div>
- </td>
- <td class="border-grey-200 border-t">
- <div class="px-2 py-4 flex items-center">
- <span
- class="tooltip cursor-pointer outline-none"
- data-tippy-content="Click to copy"
- v-clipboard="() => getAliasEmail(alias)"
- v-clipboard:success="clipboardSuccess"
- v-clipboard:error="clipboardError"
- >
- <span class="font-semibold text-indigo-800">{{
- alias.local_part | truncate(36)
- }}</span>
- <span class="block text-grey-400 text-sm">{{
- getAliasEmail(alias) | truncate(40)
- }}</span>
- </span>
- </div>
- </td>
- <td class="border-grey-200 border-t">
- <div class="px-2 flex items-center">
- <span
- v-if="alias.recipients.length && alias.id !== recipientsAliasToEdit.id"
- class="tooltip outline-none"
- :data-tippy-content="recipientsTooltip(alias.recipients)"
- >{{ alias.recipients[0].email | truncate(25) }}
- <span
- v-if="alias.recipients.length > 1"
- class="block text-center text-grey-500 text-sm"
- >
- + {{ alias.recipients.length - 1 }}</span
- >
- </span>
- <span v-else-if="alias.id === recipientsAliasToEdit.id">{{
- aliasRecipientsToEdit.length ? aliasRecipientsToEdit.length : '1'
- }}</span>
- <span
- v-else
- class="py-1 px-2 text-sm bg-yellow-200 text-yellow-900 rounded-full tooltip outline-none"
- :data-tippy-content="defaultRecipient.email"
- >default</span
- >
- <icon
- name="edit"
- class="ml-2 block w-6 h-6 text-grey-200 fill-current cursor-pointer"
- @click.native="openAliasRecipientsModal(alias)"
- />
- </div>
- </td>
- <td class="border-grey-200 border-t">
- <div class="px-2 py-4 text-sm">
- <div
- v-if="aliasIdToEdit === alias.id"
- class="w-full flex items-center justify-between"
- >
- <input
- @keyup.enter="editAlias(alias)"
- @keyup.esc="aliasIdToEdit = aliasDescriptionToEdit = ''"
- v-model="aliasDescriptionToEdit"
- type="text"
- class="appearance-none bg-grey-100 border text-grey-700 focus:outline-none rounded px-2 py-1"
- :class="
- aliasDescriptionToEdit.length > 100 ? 'border-red-500' : 'border-transparent'
- "
- placeholder="Add description"
- tabindex="0"
- autofocus
- />
- <icon
- name="close"
- class="inline-block w-6 h-6 text-red-300 fill-current cursor-pointer"
- @click.native="aliasIdToEdit = aliasDescriptionToEdit = ''"
- />
- <icon
- name="save"
- class="inline-block w-6 h-6 text-cyan-500 fill-current cursor-pointer"
- @click.native="editAlias(alias)"
- />
- </div>
- <div v-else-if="alias.description" class="flex items-center justify-around">
- <span
- class="tooltip outline-none"
- :data-tippy-content="alias.description"
- v-clipboard="() => alias.description"
- v-clipboard:success="clipboardSuccess"
- v-clipboard:error="clipboardError"
- >
- <icon
- name="desc"
- class="inline-block w-6 h-6 text-grey-200 fill-current cursor-pointer"
- />
- </span>
- <icon
- name="edit"
- class="inline-block w-6 h-6 text-grey-200 fill-current cursor-pointer"
- @click.native="
- ;(aliasIdToEdit = alias.id), (aliasDescriptionToEdit = alias.description)
- "
- />
- </div>
- <div v-else class="w-full flex justify-center">
- <icon
- name="plus"
- class="block w-6 h-6 text-grey-200 fill-current cursor-pointer"
- @click.native="aliasIdToEdit = alias.id"
- />
- </div>
- </div>
- </td>
- <td class="border-grey-200 border-t">
- <div class="px-2 py-4 flex items-center justify-center font-semibold text-indigo-800">
- {{ alias.emails_forwarded }}
- </div>
- </td>
- <td class="border-grey-200 border-t">
- <div class="px-2 py-4 flex items-center justify-center font-semibold text-indigo-800">
- {{ alias.emails_blocked }}
- </div>
- </td>
- <td class="border-grey-200 border-t">
- <div class="px-2 py-4 flex items-center justify-center font-semibold text-indigo-800">
- {{ alias.emails_replied }}
- </div>
- </td>
- <td class="border-grey-200 border-t">
- <div class="px-2 py-4 flex items-center justify-center">
- <Toggle
- v-model="alias.active"
- @on="activateAlias(alias)"
- @off="deactivateAlias(alias)"
- />
- </div>
- </td>
- <td class="border-grey-200 border-t w-px">
- <div class="px-4 flex items-center justify-center outline-none" tabindex="-1">
- <icon
- name="trash"
- class="block w-6 h-6 text-grey-200 fill-current cursor-pointer"
- @click.native="openDeleteModal(alias.id)"
- />
- </div>
- </td>
- </tr>
- <tr v-if="queriedAliases.length === 0">
- <td
- class="border-grey-200 border-t px-6 py-4 text-center h-24 text-lg text-grey-700"
- colspan="9"
- >
- No aliases found for that search!
- </td>
- </tr>
- </table>
- <div v-else class="p-8 text-center text-lg text-grey-700">
- <h1 class="mb-6 text-2xl text-indigo-800 font-semibold">
- It doesn't look like you have any aliases yet!
- </h1>
- <div class="mx-auto mb-6 w-24 border-b-2 border-grey-200"></div>
- <p class="mb-4">
- There are two ways to create new aliases.
- </p>
- <h3 class="mb-4 text-xl text-indigo-800 font-semibold">
- Option 1: Create aliases on the fly
- </h3>
- <p class="mb-4">
- To create aliases on the fly all you have to do is make up any new alias and give that out
- instead of your real email address.
- </p>
- <p class="mb-4">
- Let's say you're signing up to <b>example.com</b> you could enter
- <b>example@{{ subdomain }}</b> as your email address.
- </p>
- <p class="mb-4">
- The alias will show up here automatically as soon as it has forwarded its first email.
- </p>
- <p class="mb-4">
- If you start receiving spam to the alias you can simply deactivate it or delete it all
- together!
- </p>
- <p class="mb-4">
- Try it out now by sending an email to <b>first@{{ subdomain }}</b> and then refresh this
- page.
- </p>
- <h3 class="mb-4 text-xl text-indigo-800 font-semibold">
- Option 2: Generate a unique random alias
- </h3>
- <p class="mb-4">
- You can click the button above to generate a random UUID alias that will look something
- like this:
- </p>
- <p class="mb-4">
- <b>86064c92-da41-443e-a2bf-5a7b0247842f@{{ domain }}</b>
- </p>
- <p>
- Useful if you do not wish to include your username in the email as a potential link
- between aliases.
- </p>
- </div>
- </div>
- <Modal :open="generateAliasModalOpen" @close="generateAliasModalOpen = false">
- <div class="max-w-lg w-full bg-white rounded-lg shadow-2xl p-6">
- <h2
- class="font-semibold text-grey-900 text-2xl leading-tight border-b-2 border-grey-100 pb-4"
- >
- Generate new UUID alias
- </h2>
- <p class="mt-4 text-grey-700">
- This will generate a new unique alias in the form of
- <span class="text-sm block mt-2 font-semibold"
- >86064c92-da41-443e-a2bf-5a7b0247842f@{{ domain }}</span
- >
- </p>
- <p class="mt-2 text-grey-700">
- Other aliases e.g. alias@{{ subdomain }} are created automatically when they receive their
- first email.
- </p>
- <label for="banner_location" class="block text-grey-700 text-sm my-2">
- Alias Domain:
- </label>
- <div class="block relative w-full">
- <select
- v-model="generateAliasDomain"
- class="block appearance-none w-full text-grey-700 bg-grey-100 p-3 pr-8 rounded shadow focus:shadow-outline"
- required
- >
- <option v-for="domainOption in allDomains" :key="domainOption" :value="domainOption">{{
- domainOption
- }}</option>
- </select>
- <div
- class="pointer-events-none absolute inset-y-0 right-0 flex items-center px-2 text-gray-700"
- >
- <svg
- class="fill-current h-4 w-4"
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 20 20"
- >
- <path
- d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"
- />
- </svg>
- </div>
- </div>
- <div class="mt-6">
- <button
- @click="generateNewAlias"
- class="bg-cyan-400 hover:bg-cyan-300 text-cyan-900 font-bold py-3 px-4 rounded focus:outline-none"
- :class="generateAliasLoading ? 'cursor-not-allowed' : ''"
- :disabled="generateAliasLoading"
- >
- Generate Alias
- <loader v-if="generateAliasLoading" />
- </button>
- <button
- @click="generateAliasModalOpen = false"
- class="ml-4 px-4 py-3 text-grey-800 font-semibold bg-white hover:bg-grey-50 border border-grey-100 rounded focus:outline-none"
- >
- Cancel
- </button>
- </div>
- </div>
- </Modal>
- <Modal :open="editAliasRecipientsModalOpen" @close="closeAliasRecipientsModal">
- <div class="max-w-lg w-full bg-white rounded-lg shadow-2xl px-6 py-6">
- <h2
- class="font-semibold text-grey-900 text-2xl leading-tight border-b-2 border-grey-100 pb-4"
- >
- Update Alias Recipients
- </h2>
- <p class="my-4 text-grey-700">
- Select the recipients for this alias. You can choose multiple recipients. Leave it empty
- if you would like to use the default recipient.
- </p>
- <multiselect
- v-model="aliasRecipientsToEdit"
- :options="recipientOptions"
- :multiple="true"
- :close-on-select="true"
- :clear-on-select="false"
- :searchable="true"
- :max="10"
- placeholder="Select recipients"
- label="email"
- track-by="email"
- :preselect-first="false"
- :show-labels="false"
- >
- </multiselect>
- <div class="mt-6">
- <button
- type="button"
- @click="editAliasRecipients()"
- class="px-4 py-3 text-cyan-900 font-semibold bg-cyan-400 hover:bg-cyan-300 border border-transparent rounded focus:outline-none"
- :class="editAliasRecipientsLoading ? 'cursor-not-allowed' : ''"
- :disabled="editAliasRecipientsLoading"
- >
- Update Recipients
- <loader v-if="editAliasRecipientsLoading" />
- </button>
- <button
- @click="closeAliasRecipientsModal()"
- class="ml-4 px-4 py-3 text-grey-800 font-semibold bg-white hover:bg-grey-50 border border-grey-100 rounded focus:outline-none"
- >
- Cancel
- </button>
- </div>
- </div>
- </Modal>
- <Modal :open="deleteAliasModalOpen" @close="closeDeleteModal">
- <div class="max-w-lg w-full bg-white rounded-lg shadow-2xl px-6 py-6">
- <h2
- class="font-semibold text-grey-900 text-2xl leading-tight border-b-2 border-grey-100 pb-4"
- >
- Delete alias
- </h2>
- <p class="mt-4 text-grey-700">
- Are you sure you want to delete this alias? This action cannot be undone.
- </p>
- <div class="mt-6">
- <button
- type="button"
- @click="deleteAlias(aliasIdToDelete)"
- class="px-4 py-3 text-white font-semibold bg-red-500 hover:bg-red-600 border border-transparent rounded focus:outline-none"
- :class="deleteAliasLoading ? 'cursor-not-allowed' : ''"
- :disabled="deleteAliasLoading"
- >
- Delete alias
- <loader v-if="deleteAliasLoading" />
- </button>
- <button
- @click="closeDeleteModal"
- class="ml-4 px-4 py-3 text-grey-800 font-semibold bg-white hover:bg-grey-50 border border-grey-100 rounded focus:outline-none"
- >
- Cancel
- </button>
- </div>
- </div>
- </Modal>
- </div>
- </template>
- <script>
- import Modal from './../components/Modal.vue'
- import Toggle from './../components/Toggle.vue'
- import tippy from 'tippy.js'
- import Multiselect from 'vue-multiselect'
- export default {
- props: {
- defaultRecipient: {
- type: Object,
- required: true,
- },
- initialAliases: {
- type: Array,
- required: true,
- },
- recipientOptions: {
- type: Array,
- required: true,
- },
- totalForwarded: {
- type: Number,
- required: true,
- },
- totalBlocked: {
- type: Number,
- required: true,
- },
- totalReplies: {
- type: Number,
- required: true,
- },
- domain: {
- type: String,
- required: true,
- },
- subdomain: {
- type: String,
- required: true,
- },
- bandwidthMb: {
- type: Number,
- required: true,
- },
- month: {
- type: String,
- required: true,
- },
- allDomains: {
- type: Array,
- required: true,
- },
- },
- components: {
- Modal,
- Toggle,
- Multiselect,
- },
- mounted() {
- this.addTooltips()
- },
- data() {
- return {
- aliases: this.initialAliases,
- search: '',
- aliasIdToEdit: '',
- aliasDescriptionToEdit: '',
- aliasIdToDelete: '',
- deleteAliasLoading: false,
- deleteAliasModalOpen: false,
- currentSort: 'created_at',
- currentSortDir: 'desc',
- editAliasRecipientsLoading: false,
- editAliasRecipientsModalOpen: false,
- generateAliasModalOpen: false,
- generateAliasLoading: false,
- generateAliasDomain: this.domain,
- recipientsAliasToEdit: {},
- aliasRecipientsToEdit: [],
- }
- },
- watch: {
- queriedAliases: _.debounce(function() {
- this.addTooltips()
- }, 50),
- aliasIdToEdit: _.debounce(function() {
- this.addTooltips()
- }, 50),
- editAliasRecipientsModalOpen: _.debounce(function() {
- this.addTooltips()
- }, 50),
- },
- computed: {
- queriedAliases() {
- return _.filter(this.aliases, alias => alias.email.includes(this.search))
- },
- totalActive() {
- return _.filter(this.aliases, 'active').length
- },
- totalInactive() {
- return _.reject(this.aliases, 'active').length
- },
- },
- methods: {
- addTooltips() {
- tippy('.tooltip', {
- arrow: true,
- arrowType: 'round',
- })
- },
- recipientsTooltip(recipients) {
- return _.reduce(recipients, (list, recipient) => list + `${recipient.email}<br>`, '')
- },
- isCurrentSort(col, dir) {
- return this.currentSort === col && this.currentSortDir === dir
- },
- openDeleteModal(id) {
- this.deleteAliasModalOpen = true
- this.aliasIdToDelete = id
- },
- closeDeleteModal() {
- this.deleteAliasModalOpen = false
- this.aliasIdToDelete = ''
- },
- deleteAlias(id) {
- this.deleteAliasLoading = true
- axios
- .delete(`/aliases/${id}`)
- .then(response => {
- this.aliases = _.filter(this.aliases, aliases => aliases.id !== id)
- this.deleteAliasModalOpen = false
- this.deleteAliasLoading = false
- })
- .catch(error => {
- this.error()
- this.deleteAliasModalOpen = false
- this.deleteAliasLoading = false
- })
- },
- sort(col, dir) {
- if (this.currentSort === col && this.currentSortDir === dir) {
- this.currentSort = 'created_at'
- this.currentSortDir = 'desc'
- } else {
- this.currentSort = col
- this.currentSortDir = dir
- }
- this.aliases = _.orderBy(this.aliases, [this.currentSort], [this.currentSortDir])
- },
- reSort() {
- this.aliases = _.orderBy(this.aliases, [this.currentSort], [this.currentSortDir])
- },
- openAliasRecipientsModal(alias) {
- this.editAliasRecipientsModalOpen = true
- this.recipientsAliasToEdit = alias
- this.aliasRecipientsToEdit = alias.recipients
- },
- closeAliasRecipientsModal() {
- this.editAliasRecipientsModalOpen = false
- this.recipientsAliasToEdit = {}
- this.aliasRecipientsToEdit = []
- },
- editAliasRecipients() {
- this.editAliasRecipientsLoading = true
- axios
- .post(
- '/alias-recipients',
- JSON.stringify({
- alias_id: this.recipientsAliasToEdit.id,
- recipient_ids: _.map(this.aliasRecipientsToEdit, recipient => recipient.id),
- }),
- {
- headers: { 'Content-Type': 'application/json' },
- }
- )
- .then(response => {
- let alias = _.find(this.aliases, ['id', this.recipientsAliasToEdit.id])
- alias.recipients = this.aliasRecipientsToEdit
- this.editAliasRecipientsModalOpen = false
- this.editAliasRecipientsLoading = false
- this.recipientsAliasToEdit = {}
- this.aliasRecipientsToEdit = []
- this.success('Alias recipients updated')
- })
- .catch(error => {
- this.editAliasRecipientsModalOpen = false
- this.editAliasRecipientsLoading = false
- this.recipientsAliasToEdit = {}
- this.aliasRecipientsToEdit = []
- this.error()
- })
- },
- generateNewAlias() {
- this.generateAliasLoading = true
- axios
- .post(
- '/aliases',
- JSON.stringify({
- domain: this.generateAliasDomain,
- }),
- {
- headers: { 'Content-Type': 'application/json' },
- }
- )
- .then(({ data }) => {
- this.generateAliasLoading = false
- this.aliases.push(data.data)
- this.reSort()
- this.generateAliasModalOpen = false
- this.success('New alias generated successfully')
- })
- .catch(error => {
- this.generateAliasLoading = false
- if (error.response.status === 429) {
- this.error('You have reached your hourly limit for creating new aliases')
- } else {
- this.error()
- }
- })
- },
- editAlias(alias) {
- if (this.aliasDescriptionToEdit.length > 100) {
- return this.error('Description cannot be more than 100 characters')
- }
- axios
- .patch(
- `/aliases/${alias.id}`,
- JSON.stringify({
- description: this.aliasDescriptionToEdit,
- }),
- {
- headers: { 'Content-Type': 'application/json' },
- }
- )
- .then(response => {
- alias.description = this.aliasDescriptionToEdit
- this.aliasIdToEdit = ''
- this.aliasDescriptionToEdit = ''
- this.success('Alias description updated')
- })
- .catch(error => {
- this.aliasIdToEdit = ''
- this.aliasDescriptionToEdit = ''
- this.error()
- })
- },
- activateAlias(alias) {
- axios
- .post(
- `/active-aliases`,
- JSON.stringify({
- id: alias.id,
- }),
- {
- headers: { 'Content-Type': 'application/json' },
- }
- )
- .then(response => {
- //
- })
- .catch(error => {
- this.error()
- })
- },
- deactivateAlias(alias) {
- axios
- .delete(`/active-aliases/${alias.id}`)
- .then(response => {
- //
- })
- .catch(error => {
- this.error()
- })
- },
- getAliasEmail(alias) {
- return alias.extension
- ? `${alias.local_part}+${alias.extension}@${alias.domain}`
- : alias.email
- },
- clipboardSuccess() {
- this.success('Copied to clipboard')
- },
- clipboardError() {
- this.error('Could not copy to clipboard')
- },
- success(text = '') {
- this.$notify({
- title: 'Success',
- text: text,
- type: 'success',
- })
- },
- error(text = 'An error has occurred, please try again later') {
- this.$notify({
- title: 'Error',
- text: text,
- type: 'error',
- })
- },
- },
- }
- </script>
- <style src="vue-multiselect/dist/vue-multiselect.min.css"></style>
|