mirror of
https://github.com/VueFileManager/vuefilemanager.git
synced 2026-04-21 17:12:15 +00:00
added prettier
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<div class="lg:flex md:h-screen md:overflow-hidden dark:bg-dark-background bg-light-background">
|
||||
<!--On Top of App Components-->
|
||||
<div class="bg-light-background dark:bg-dark-background md:h-screen md:overflow-hidden lg:flex">
|
||||
<!--On Top of App Components-->
|
||||
<FilePreview />
|
||||
<Spotlight />
|
||||
<Spotlight />
|
||||
|
||||
<!--Mobile Navigation-->
|
||||
<MobileNavigation />
|
||||
@@ -11,176 +11,187 @@
|
||||
<ConfirmPopup />
|
||||
|
||||
<!-- Create language popup -->
|
||||
<CreateLanguage/>
|
||||
<CreateLanguage />
|
||||
|
||||
<!--Navigation Sidebar-->
|
||||
<SidebarNavigation/>
|
||||
<SidebarNavigation />
|
||||
|
||||
<MobileNavigationToolbar />
|
||||
<MobileNavigationToolbar />
|
||||
|
||||
<ContentSidebar>
|
||||
<ContentGroup v-for="(menu, i) in nav" :key="i" :title="menu.groupTitle" :slug="menu.groupTitle" :can-collapse="false">
|
||||
<router-link v-for="(item, i) in menu.groupLinks" :key="i" :to="{name: item.route}" class="flex items-center py-2.5" :class="{'router-link-active': item.linkActivation && item.linkActivation.includes($router.currentRoute.fullPath.split('/')[2])}">
|
||||
<box-icon v-if="item.icon === 'box'" size="17" class="mr-2.5 vue-feather icon-active" />
|
||||
<users-icon v-if="item.icon === 'users'" size="17" class="mr-2.5 vue-feather icon-active" />
|
||||
<settings-icon v-if="item.icon === 'settings'" size="17" class="mr-2.5 vue-feather icon-active" />
|
||||
<monitor-icon v-if="item.icon === 'monitor'" size="17" class="mr-2.5 vue-feather icon-active" />
|
||||
<globe-icon v-if="item.icon === 'globe'" size="17" class="mr-2.5 vue-feather icon-active" />
|
||||
<credit-card-icon v-if="item.icon === 'card'" size="17" class="mr-2.5 vue-feather icon-active" />
|
||||
<database-icon v-if="item.icon === 'database'" size="17" class="mr-2.5 vue-feather icon-active" />
|
||||
<dollar-sign-icon v-if="item.icon === 'dollar'" size="17" class="mr-2.5 vue-feather icon-active" />
|
||||
<file-text-icon v-if="item.icon === 'file-text'" size="17" class="mr-2.5 vue-feather icon-active" />
|
||||
<ContentGroup v-for="(menu, i) in nav" :key="i" :title="menu.groupTitle" :slug="menu.groupTitle" :can-collapse="false">
|
||||
<router-link
|
||||
v-for="(item, i) in menu.groupLinks"
|
||||
:key="i"
|
||||
:to="{ name: item.route }"
|
||||
class="flex items-center py-2.5"
|
||||
:class="{
|
||||
'router-link-active': item.linkActivation && item.linkActivation.includes($router.currentRoute.fullPath.split('/')[2]),
|
||||
}"
|
||||
>
|
||||
<box-icon v-if="item.icon === 'box'" size="17" class="vue-feather icon-active mr-2.5" />
|
||||
<users-icon v-if="item.icon === 'users'" size="17" class="vue-feather icon-active mr-2.5" />
|
||||
<settings-icon v-if="item.icon === 'settings'" size="17" class="vue-feather icon-active mr-2.5" />
|
||||
<monitor-icon v-if="item.icon === 'monitor'" size="17" class="vue-feather icon-active mr-2.5" />
|
||||
<globe-icon v-if="item.icon === 'globe'" size="17" class="vue-feather icon-active mr-2.5" />
|
||||
<credit-card-icon v-if="item.icon === 'card'" size="17" class="vue-feather icon-active mr-2.5" />
|
||||
<database-icon v-if="item.icon === 'database'" size="17" class="vue-feather icon-active mr-2.5" />
|
||||
<dollar-sign-icon v-if="item.icon === 'dollar'" size="17" class="vue-feather icon-active mr-2.5" />
|
||||
<file-text-icon v-if="item.icon === 'file-text'" size="17" class="vue-feather icon-active mr-2.5" />
|
||||
|
||||
<b class="font-bold text-xs text-active">
|
||||
{{ item.title }}
|
||||
</b>
|
||||
</router-link>
|
||||
<b class="text-active text-xs font-bold">
|
||||
{{ item.title }}
|
||||
</b>
|
||||
</router-link>
|
||||
</ContentGroup>
|
||||
</ContentSidebar>
|
||||
|
||||
<router-view class="lg:pt-6 md:px-6 px-2.5 lg:pb-0 pb-12 w-full overflow-x-hidden relative" />
|
||||
<router-view class="relative w-full overflow-x-hidden px-2.5 pb-12 md:px-6 lg:pt-6 lg:pb-0" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MobileNavigationToolbar from "./MobileNavigationToolbar";
|
||||
import FilePreview from "../components/FilePreview/FilePreview";
|
||||
import Spotlight from "../components/Spotlight/Spotlight";
|
||||
import { DollarSignIcon, HelpCircleIcon, RefreshCwIcon, UsersIcon, SettingsIcon, FileTextIcon, CreditCardIcon, DatabaseIcon, BoxIcon, MonitorIcon, GlobeIcon } from 'vue-feather-icons'
|
||||
import SidebarNavigation from "../components/Sidebar/SidebarNavigation";
|
||||
import MobileNavigation from "../components/Others/MobileNavigation";
|
||||
import ContentSidebar from "../components/Sidebar/ContentSidebar";
|
||||
import CreateLanguage from "../components/Others/CreateLanguage";
|
||||
import ContentGroup from "../components/Sidebar/ContentGroup";
|
||||
import ConfirmPopup from "../components/Others/Popup/ConfirmPopup";
|
||||
import { mapGetters } from 'vuex'
|
||||
import FilePreview from '../components/FilePreview/FilePreview'
|
||||
import CreateLanguage from '../components/Others/CreateLanguage'
|
||||
import MobileNavigation from '../components/Others/MobileNavigation'
|
||||
import ConfirmPopup from '../components/Others/Popup/ConfirmPopup'
|
||||
import ContentGroup from '../components/Sidebar/ContentGroup'
|
||||
import ContentSidebar from '../components/Sidebar/ContentSidebar'
|
||||
import SidebarNavigation from '../components/Sidebar/SidebarNavigation'
|
||||
import Spotlight from '../components/Spotlight/Spotlight'
|
||||
import MobileNavigationToolbar from './MobileNavigationToolbar'
|
||||
import {
|
||||
BoxIcon,
|
||||
CreditCardIcon,
|
||||
DatabaseIcon,
|
||||
DollarSignIcon,
|
||||
FileTextIcon,
|
||||
GlobeIcon,
|
||||
HelpCircleIcon,
|
||||
MonitorIcon,
|
||||
RefreshCwIcon,
|
||||
SettingsIcon,
|
||||
UsersIcon,
|
||||
} from 'vue-feather-icons'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Admin',
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'isVisibleNavigationBars',
|
||||
'config',
|
||||
]),
|
||||
nav() {
|
||||
let subscriptionLinks = {
|
||||
metered: [
|
||||
{
|
||||
title: this.$t('Payments'),
|
||||
route: 'PaymentSettings',
|
||||
icon: 'card',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_menu.plans'),
|
||||
route: 'Plans',
|
||||
icon: 'database',
|
||||
linkActivation: [
|
||||
'plans', 'plan'
|
||||
],
|
||||
},
|
||||
{
|
||||
title: this.$t('Transactions'),
|
||||
route: 'Invoices',
|
||||
icon: 'file-text',
|
||||
},
|
||||
],
|
||||
fixed: [
|
||||
{
|
||||
title: this.$t('Payments'),
|
||||
route: 'PaymentSettings',
|
||||
icon: 'card',
|
||||
},
|
||||
{
|
||||
title: this.$t('Subscriptions'),
|
||||
route: 'Subscriptions',
|
||||
icon: 'dollar',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_menu.plans'),
|
||||
route: 'Plans',
|
||||
icon: 'database',
|
||||
linkActivation: [
|
||||
'plans', 'plan'
|
||||
],
|
||||
},
|
||||
{
|
||||
title: this.$t('Transactions'),
|
||||
route: 'Invoices',
|
||||
icon: 'file-text',
|
||||
},
|
||||
],
|
||||
}[this.config.subscriptionType]
|
||||
export default {
|
||||
name: 'Admin',
|
||||
computed: {
|
||||
...mapGetters(['isVisibleNavigationBars', 'config']),
|
||||
nav() {
|
||||
let subscriptionLinks = {
|
||||
metered: [
|
||||
{
|
||||
title: this.$t('Payments'),
|
||||
route: 'PaymentSettings',
|
||||
icon: 'card',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_menu.plans'),
|
||||
route: 'Plans',
|
||||
icon: 'database',
|
||||
linkActivation: ['plans', 'plan'],
|
||||
},
|
||||
{
|
||||
title: this.$t('Transactions'),
|
||||
route: 'Invoices',
|
||||
icon: 'file-text',
|
||||
},
|
||||
],
|
||||
fixed: [
|
||||
{
|
||||
title: this.$t('Payments'),
|
||||
route: 'PaymentSettings',
|
||||
icon: 'card',
|
||||
},
|
||||
{
|
||||
title: this.$t('Subscriptions'),
|
||||
route: 'Subscriptions',
|
||||
icon: 'dollar',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_menu.plans'),
|
||||
route: 'Plans',
|
||||
icon: 'database',
|
||||
linkActivation: ['plans', 'plan'],
|
||||
},
|
||||
{
|
||||
title: this.$t('Transactions'),
|
||||
route: 'Invoices',
|
||||
icon: 'file-text',
|
||||
},
|
||||
],
|
||||
}[this.config.subscriptionType]
|
||||
|
||||
return [
|
||||
{
|
||||
groupCollapsable: false,
|
||||
groupTitle: this.$t('global.admin'),
|
||||
groupLinks: [
|
||||
{
|
||||
title: this.$t('admin_menu.dashboard'),
|
||||
route: 'Dashboard',
|
||||
icon: 'box',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_menu.users'),
|
||||
route: 'Users',
|
||||
icon: 'users',
|
||||
linkActivation: [
|
||||
'users', 'user'
|
||||
],
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_menu.settings'),
|
||||
route: 'AppSettings',
|
||||
icon: 'settings',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupCollapsable: false,
|
||||
groupTitle: this.$t('Content'),
|
||||
groupLinks: [
|
||||
{
|
||||
title: this.$t('admin_menu.pages'),
|
||||
route: 'Pages',
|
||||
icon: 'monitor',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_menu.languages'),
|
||||
route: 'Language',
|
||||
icon: 'globe',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupCollapsable: false,
|
||||
groupTitle: this.$t('Subscription'),
|
||||
groupLinks: subscriptionLinks,
|
||||
},
|
||||
]
|
||||
}
|
||||
return [
|
||||
{
|
||||
groupCollapsable: false,
|
||||
groupTitle: this.$t('global.admin'),
|
||||
groupLinks: [
|
||||
{
|
||||
title: this.$t('admin_menu.dashboard'),
|
||||
route: 'Dashboard',
|
||||
icon: 'box',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_menu.users'),
|
||||
route: 'Users',
|
||||
icon: 'users',
|
||||
linkActivation: ['users', 'user'],
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_menu.settings'),
|
||||
route: 'AppSettings',
|
||||
icon: 'settings',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupCollapsable: false,
|
||||
groupTitle: this.$t('Content'),
|
||||
groupLinks: [
|
||||
{
|
||||
title: this.$t('admin_menu.pages'),
|
||||
route: 'Pages',
|
||||
icon: 'monitor',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_menu.languages'),
|
||||
route: 'Language',
|
||||
icon: 'globe',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupCollapsable: false,
|
||||
groupTitle: this.$t('Subscription'),
|
||||
groupLinks: subscriptionLinks,
|
||||
},
|
||||
]
|
||||
},
|
||||
components: {
|
||||
MobileNavigationToolbar,
|
||||
FilePreview,
|
||||
Spotlight,
|
||||
SidebarNavigation,
|
||||
MobileNavigation,
|
||||
CreateLanguage,
|
||||
ContentSidebar,
|
||||
DollarSignIcon,
|
||||
HelpCircleIcon,
|
||||
RefreshCwIcon,
|
||||
CreditCardIcon,
|
||||
FileTextIcon,
|
||||
ContentGroup,
|
||||
DatabaseIcon,
|
||||
SettingsIcon,
|
||||
MonitorIcon,
|
||||
UsersIcon,
|
||||
GlobeIcon,
|
||||
ConfirmPopup,
|
||||
BoxIcon,
|
||||
},
|
||||
}
|
||||
},
|
||||
components: {
|
||||
MobileNavigationToolbar,
|
||||
FilePreview,
|
||||
Spotlight,
|
||||
SidebarNavigation,
|
||||
MobileNavigation,
|
||||
CreateLanguage,
|
||||
ContentSidebar,
|
||||
DollarSignIcon,
|
||||
HelpCircleIcon,
|
||||
RefreshCwIcon,
|
||||
CreditCardIcon,
|
||||
FileTextIcon,
|
||||
ContentGroup,
|
||||
DatabaseIcon,
|
||||
SettingsIcon,
|
||||
MonitorIcon,
|
||||
UsersIcon,
|
||||
GlobeIcon,
|
||||
ConfirmPopup,
|
||||
BoxIcon,
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,52 +1,51 @@
|
||||
<template>
|
||||
<div>
|
||||
<!--Page Tab links-->
|
||||
<div class="card shadow-card z-10" style="padding-bottom: 0; padding-top: 0;">
|
||||
<CardNavigation :pages="pages" class="-mx-1" />
|
||||
</div>
|
||||
<!--Page Tab links-->
|
||||
<div class="card z-10 shadow-card" style="padding-bottom: 0; padding-top: 0">
|
||||
<CardNavigation :pages="pages" class="-mx-1" />
|
||||
</div>
|
||||
|
||||
<!--Page Content-->
|
||||
<router-view />
|
||||
<!--Page Content-->
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CardNavigation from "../../../components/Admin/CardNavigation";
|
||||
import CardNavigation from '../../../components/Admin/CardNavigation'
|
||||
|
||||
|
||||
export default {
|
||||
name: 'AppSettings',
|
||||
components: {
|
||||
CardNavigation,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
title: this.$t('admin_settings.tabs.others'),
|
||||
route: 'AppOthers',
|
||||
},
|
||||
{
|
||||
title: this.$t('Login & Registration'),
|
||||
route: 'AppSignInUp',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_settings.tabs.appearance'),
|
||||
route: 'AppAppearance',
|
||||
},
|
||||
{
|
||||
title: this.$t('Homepage'),
|
||||
route: 'AppIndex',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_settings.tabs.email'),
|
||||
route: 'AppEmail',
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$router.push({name: 'AppOthers'})
|
||||
}
|
||||
}
|
||||
export default {
|
||||
name: 'AppSettings',
|
||||
components: {
|
||||
CardNavigation,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
title: this.$t('admin_settings.tabs.others'),
|
||||
route: 'AppOthers',
|
||||
},
|
||||
{
|
||||
title: this.$t('Login & Registration'),
|
||||
route: 'AppSignInUp',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_settings.tabs.appearance'),
|
||||
route: 'AppAppearance',
|
||||
},
|
||||
{
|
||||
title: this.$t('Homepage'),
|
||||
route: 'AppIndex',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_settings.tabs.email'),
|
||||
route: 'AppEmail',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$router.push({ name: 'AppOthers' })
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,109 +1,126 @@
|
||||
<template>
|
||||
<PageTab :is-loading="isLoading">
|
||||
<div v-if="app" class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('admin_settings.appearance.section_general') }}
|
||||
</FormLabel>
|
||||
<div v-if="app" class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('admin_settings.appearance.section_general') }}
|
||||
</FormLabel>
|
||||
|
||||
<AppInputSwitch :title="$t('color_theme')" :description="$t('color_theme_description')">
|
||||
<input @input="$updateText('/admin/settings', 'app_color', app.color)" v-model="app.color" :placeholder="$t('admin_settings.appearance.title_plac')" type="color"/>
|
||||
</AppInputSwitch>
|
||||
<AppInputSwitch :title="$t('color_theme')" :description="$t('color_theme_description')">
|
||||
<input @input="$updateText('/admin/settings', 'app_color', app.color)" v-model="app.color" :placeholder="$t('admin_settings.appearance.title_plac')" type="color" />
|
||||
</AppInputSwitch>
|
||||
|
||||
<AppInputText :title="$t('admin_settings.appearance.title')">
|
||||
<input @input="$updateText('/admin/settings', 'app_title', app.title)" v-model="app.title" :placeholder="$t('admin_settings.appearance.title_plac')" type="text" class="focus-border-theme input-dark"/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('admin_settings.appearance.title')">
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'app_title', app.title)"
|
||||
v-model="app.title"
|
||||
:placeholder="$t('admin_settings.appearance.title_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
|
||||
<AppInputText :title="$t('admin_settings.appearance.description')" :is-last="true">
|
||||
<input @input="$updateText('/admin/settings', 'app_description', app.description)" v-model="app.description" :placeholder="$t('admin_settings.appearance.description_plac')" type="text" class="focus-border-theme input-dark"/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
<div v-if="app" class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Branding') }}
|
||||
</FormLabel>
|
||||
<AppInputText :title="$t('admin_settings.appearance.description')" :is-last="true">
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'app_description', app.description)"
|
||||
v-model="app.description"
|
||||
:placeholder="$t('admin_settings.appearance.description_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
<div v-if="app" class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Branding') }}
|
||||
</FormLabel>
|
||||
|
||||
<AppInputText :title="$t('admin_settings.appearance.logo')">
|
||||
<ImageInput @input="$updateImage('/admin/settings', 'app_logo', app.logo)" :image="$getImage(app.logo)" v-model="app.logo"/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('admin_settings.appearance.logo')">
|
||||
<ImageInput @input="$updateImage('/admin/settings', 'app_logo', app.logo)" :image="$getImage(app.logo)" v-model="app.logo" />
|
||||
</AppInputText>
|
||||
|
||||
<AppInputText :title="$t('admin_settings.appearance.logo_horizontal')">
|
||||
<ImageInput @input="$updateImage('/admin/settings', 'app_logo_horizontal', app.logo_horizontal)" :image="$getImage(app.logo_horizontal)" v-model="app.logo_horizontal"/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('admin_settings.appearance.logo_horizontal')">
|
||||
<ImageInput
|
||||
@input="$updateImage('/admin/settings', 'app_logo_horizontal', app.logo_horizontal)"
|
||||
:image="$getImage(app.logo_horizontal)"
|
||||
v-model="app.logo_horizontal"
|
||||
/>
|
||||
</AppInputText>
|
||||
|
||||
<AppInputText :title="$t('admin_settings.appearance.favicon')">
|
||||
<ImageInput @input="$updateImage('/admin/settings', 'app_favicon', app.favicon)" :image="$getImage(app.favicon)" v-model="app.favicon"/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('admin_settings.appearance.favicon')">
|
||||
<ImageInput @input="$updateImage('/admin/settings', 'app_favicon', app.favicon)" :image="$getImage(app.favicon)" v-model="app.favicon" />
|
||||
</AppInputText>
|
||||
|
||||
<AppInputText :title="$t('og_image')" :description="$t('og_image_description')">
|
||||
<ImageInput @input="$updateImage('/admin/settings', 'app_og_image', app.og_image)" :image="$getImage(app.og_image)" v-model="app.og_image"/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('og_image')" :description="$t('og_image_description')">
|
||||
<ImageInput @input="$updateImage('/admin/settings', 'app_og_image', app.og_image)" :image="$getImage(app.og_image)" v-model="app.og_image" />
|
||||
</AppInputText>
|
||||
|
||||
<AppInputText :title="$t('app_touch_icon')" :description="$t('app_touch_icon_description')">
|
||||
<ImageInput @input="$updateImage('/admin/settings', 'app_touch_icon', app.touch_icon)" :image="$getImage(app.touch_icon)" v-model="app.touch_icon"/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
<AppInputText :title="$t('app_touch_icon')" :description="$t('app_touch_icon_description')">
|
||||
<ImageInput @input="$updateImage('/admin/settings', 'app_touch_icon', app.touch_icon)" :image="$getImage(app.touch_icon)" v-model="app.touch_icon" />
|
||||
</AppInputText>
|
||||
</div>
|
||||
</PageTab>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AppInputSwitch from "../../../../components/Admin/AppInputSwitch";
|
||||
import AppInputText from "../../../../components/Admin/AppInputText";
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import PageTabGroup from "../../../../components/Others/Layout/PageTabGroup";
|
||||
import SelectInput from "../../../../components/Others/Forms/SelectInput";
|
||||
import ImageInput from "../../../../components/Others/Forms/ImageInput";
|
||||
import FormLabel from "../../../../components/Others/Forms/FormLabel";
|
||||
import ButtonBase from "../../../../components/FilesView/ButtonBase";
|
||||
import SetupBox from "../../../../components/Others/Forms/SetupBox";
|
||||
import PageTab from "../../../../components/Others/Layout/PageTab";
|
||||
import InfoBox from "../../../../components/Others/Forms/InfoBox";
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import axios from 'axios'
|
||||
import AppInputSwitch from '../../../../components/Admin/AppInputSwitch'
|
||||
import AppInputText from '../../../../components/Admin/AppInputText'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import PageTabGroup from '../../../../components/Others/Layout/PageTabGroup'
|
||||
import SelectInput from '../../../../components/Others/Forms/SelectInput'
|
||||
import ImageInput from '../../../../components/Others/Forms/ImageInput'
|
||||
import FormLabel from '../../../../components/Others/Forms/FormLabel'
|
||||
import ButtonBase from '../../../../components/FilesView/ButtonBase'
|
||||
import SetupBox from '../../../../components/Others/Forms/SetupBox'
|
||||
import PageTab from '../../../../components/Others/Layout/PageTab'
|
||||
import InfoBox from '../../../../components/Others/Forms/InfoBox'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'AppAppearance',
|
||||
components: {
|
||||
AppInputSwitch,
|
||||
AppInputText,
|
||||
ValidationObserver,
|
||||
ValidationProvider,
|
||||
PageTabGroup,
|
||||
SelectInput,
|
||||
ImageInput,
|
||||
ButtonBase,
|
||||
FormLabel,
|
||||
SetupBox,
|
||||
required,
|
||||
PageTab,
|
||||
InfoBox,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
app: undefined,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
axios.get('/api/admin/settings', {
|
||||
export default {
|
||||
name: 'AppAppearance',
|
||||
components: {
|
||||
AppInputSwitch,
|
||||
AppInputText,
|
||||
ValidationObserver,
|
||||
ValidationProvider,
|
||||
PageTabGroup,
|
||||
SelectInput,
|
||||
ImageInput,
|
||||
ButtonBase,
|
||||
FormLabel,
|
||||
SetupBox,
|
||||
required,
|
||||
PageTab,
|
||||
InfoBox,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
app: undefined,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
axios
|
||||
.get('/api/admin/settings', {
|
||||
params: {
|
||||
column: 'app_title|app_description|app_logo|app_favicon|app_logo_horizontal|app_color|app_og_image|app_touch_icon'
|
||||
column: 'app_title|app_description|app_logo|app_favicon|app_logo_horizontal|app_color|app_og_image|app_touch_icon',
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
this.app = {
|
||||
logo_horizontal: response.data.app_logo_horizontal,
|
||||
description: response.data.app_description,
|
||||
favicon: response.data.app_favicon,
|
||||
title: response.data.app_title,
|
||||
color: response.data.app_color,
|
||||
logo: response.data.app_logo,
|
||||
og_image: response.data.app_og_image,
|
||||
touch_icon: response.data.app_touch_icon,
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
this.app = {
|
||||
logo_horizontal: response.data.app_logo_horizontal,
|
||||
description: response.data.app_description,
|
||||
favicon: response.data.app_favicon,
|
||||
title: response.data.app_title,
|
||||
color: response.data.app_color,
|
||||
logo: response.data.app_logo,
|
||||
og_image: response.data.app_og_image,
|
||||
touch_icon: response.data.app_touch_icon,
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -7,32 +7,62 @@
|
||||
</InfoBox>
|
||||
<ValidationProvider tag="div" mode="passive" name="Mail Driver" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_settings.email.driver')" :error="errors[0]">
|
||||
<input v-model="mail.driver" :placeholder="$t('admin_settings.email.driver_plac')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
<input
|
||||
v-model="mail.driver"
|
||||
:placeholder="$t('admin_settings.email.driver_plac')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="Mail Host" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_settings.email.host')" :error="errors[0]">
|
||||
<input v-model="mail.host" :placeholder="$t('admin_settings.email.host_plac')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
<input
|
||||
v-model="mail.host"
|
||||
:placeholder="$t('admin_settings.email.host_plac')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="Mail Port" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_settings.email.port')" :error="errors[0]">
|
||||
<input v-model="mail.port" :placeholder="$t('admin_settings.email.port_plac')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
<input
|
||||
v-model="mail.port"
|
||||
:placeholder="$t('admin_settings.email.port_plac')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="Mail Username" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_settings.email.username')" :error="errors[0]">
|
||||
<input v-model="mail.username" :placeholder="$t('admin_settings.email.username_plac')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
<input
|
||||
v-model="mail.username"
|
||||
:placeholder="$t('admin_settings.email.username_plac')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="Mail Password" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_settings.email.password')" :error="errors[0]">
|
||||
<input v-model="mail.password" :placeholder="$t('admin_settings.email.password_plac')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
<input
|
||||
v-model="mail.password"
|
||||
:placeholder="$t('admin_settings.email.password_plac')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="Mail Encryption" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_settings.email.encryption')" :error="errors[0]">
|
||||
<SelectInput v-model="mail.encryption" :options="encryptionList" :placeholder="$t('admin_settings.email.encryption_plac')" :isError="errors[0]"/>
|
||||
<SelectInput v-model="mail.encryption" :options="encryptionList" :placeholder="$t('admin_settings.email.encryption_plac')" :isError="errors[0]" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ButtonBase :loading="isSendingRequest" :disabled="isSendingRequest" type="submit" button-style="theme" class="submit-button">
|
||||
@@ -43,93 +73,90 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AppInputText from "../../../../components/Admin/AppInputText";
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import PageTabGroup from "../../../../components/Others/Layout/PageTabGroup";
|
||||
import SelectInput from "../../../../components/Others/Forms/SelectInput";
|
||||
import ImageInput from "../../../../components/Others/Forms/ImageInput";
|
||||
import FormLabel from "../../../../components/Others/Forms/FormLabel";
|
||||
import ButtonBase from "../../../../components/FilesView/ButtonBase";
|
||||
import SetupBox from "../../../../components/Others/Forms/SetupBox";
|
||||
import PageTab from "../../../../components/Others/Layout/PageTab";
|
||||
import InfoBox from "../../../../components/Others/Forms/InfoBox";
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {events} from '../../../../bus'
|
||||
import axios from 'axios'
|
||||
import AppInputText from '../../../../components/Admin/AppInputText'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import PageTabGroup from '../../../../components/Others/Layout/PageTabGroup'
|
||||
import SelectInput from '../../../../components/Others/Forms/SelectInput'
|
||||
import ImageInput from '../../../../components/Others/Forms/ImageInput'
|
||||
import FormLabel from '../../../../components/Others/Forms/FormLabel'
|
||||
import ButtonBase from '../../../../components/FilesView/ButtonBase'
|
||||
import SetupBox from '../../../../components/Others/Forms/SetupBox'
|
||||
import PageTab from '../../../../components/Others/Layout/PageTab'
|
||||
import InfoBox from '../../../../components/Others/Forms/InfoBox'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { events } from '../../../../bus'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'AppAppearance',
|
||||
components: {
|
||||
AppInputText,
|
||||
ValidationObserver,
|
||||
ValidationProvider,
|
||||
PageTabGroup,
|
||||
SelectInput,
|
||||
ImageInput,
|
||||
ButtonBase,
|
||||
FormLabel,
|
||||
SetupBox,
|
||||
required,
|
||||
PageTab,
|
||||
InfoBox,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
isSendingRequest: false,
|
||||
encryptionList: [
|
||||
{
|
||||
label: 'TLS',
|
||||
value: 'tls',
|
||||
},
|
||||
{
|
||||
label: 'SSL',
|
||||
value: 'ssl',
|
||||
},
|
||||
],
|
||||
mail: {
|
||||
driver: '',
|
||||
host: '',
|
||||
port: '',
|
||||
username: '',
|
||||
password: '',
|
||||
encryption: '',
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async EmailSetupSubmit() {
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.EmailSetup.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
// Start loading
|
||||
this.isSendingRequest = true
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/admin/settings/email', this.mail)
|
||||
.then(() => {
|
||||
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.email_set'),
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
events.$emit('alert:open', {
|
||||
title: this.$t('popup_error.title'),
|
||||
message: this.$t('popup_error.message'),
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
|
||||
// End loading
|
||||
this.isSendingRequest = false
|
||||
})
|
||||
export default {
|
||||
name: 'AppAppearance',
|
||||
components: {
|
||||
AppInputText,
|
||||
ValidationObserver,
|
||||
ValidationProvider,
|
||||
PageTabGroup,
|
||||
SelectInput,
|
||||
ImageInput,
|
||||
ButtonBase,
|
||||
FormLabel,
|
||||
SetupBox,
|
||||
required,
|
||||
PageTab,
|
||||
InfoBox,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
isSendingRequest: false,
|
||||
encryptionList: [
|
||||
{
|
||||
label: 'TLS',
|
||||
value: 'tls',
|
||||
},
|
||||
{
|
||||
label: 'SSL',
|
||||
value: 'ssl',
|
||||
},
|
||||
],
|
||||
mail: {
|
||||
driver: '',
|
||||
host: '',
|
||||
port: '',
|
||||
username: '',
|
||||
password: '',
|
||||
encryption: '',
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async EmailSetupSubmit() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.EmailSetup.validate()
|
||||
|
||||
if (!isValid) return
|
||||
|
||||
// Start loading
|
||||
this.isSendingRequest = true
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/admin/settings/email', this.mail)
|
||||
.then(() => {
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.email_set'),
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
events.$emit('alert:open', {
|
||||
title: this.$t('popup_error.title'),
|
||||
message: this.$t('popup_error.message'),
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
// End loading
|
||||
this.isSendingRequest = false
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,31 +1,40 @@
|
||||
<template>
|
||||
<PageTab :is-loading="isLoading">
|
||||
|
||||
<PageTabGroup v-if="app">
|
||||
<div class="form block-form">
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Homepage') }}
|
||||
</FormLabel>
|
||||
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Homepage') }}
|
||||
</FormLabel>
|
||||
|
||||
<AppInputSwitch :title="$t('Allow Homepage')" :description="$t('When this is turned on, your visitors can visit your default homepage.')" :is-last="true">
|
||||
<SwitchInput @input="$updateText('/admin/settings', 'allow_homepage', app.allow_homepage)" v-model="app.allow_homepage" class="switch" :state="app.allow_homepage"/>
|
||||
</AppInputSwitch>
|
||||
</div>
|
||||
<AppInputSwitch :title="$t('Allow Homepage')" :description="$t('When this is turned on, your visitors can visit your default homepage.')" :is-last="true">
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'allow_homepage', app.allow_homepage)"
|
||||
v-model="app.allow_homepage"
|
||||
class="switch"
|
||||
:state="app.allow_homepage"
|
||||
/>
|
||||
</AppInputSwitch>
|
||||
</div>
|
||||
|
||||
<!--Header-->
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>Header Title</FormLabel>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<img src="/assets/images/admin/main-header.jpg" alt="Main Header" class="page-image">
|
||||
<img src="/assets/images/admin/main-header.jpg" alt="Main Header" class="page-image" />
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Title:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Title" rules="required" v-slot="{ errors }">
|
||||
<input @input="$updateText('/admin/settings', 'header_title', app.header_title)" v-model="app.header_title" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark"/>
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'header_title', app.header_title)"
|
||||
v-model="app.header_title"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -33,7 +42,13 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Description:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Description" rules="required" v-slot="{ errors }">
|
||||
<textarea @input="$updateText('/admin/settings', 'header_description', app.header_description)" rows="2" v-model="app.header_description" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark"></textarea>
|
||||
<textarea
|
||||
@input="$updateText('/admin/settings', 'header_description', app.header_description)"
|
||||
rows="2"
|
||||
v-model="app.header_description"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
></textarea>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -47,25 +62,33 @@
|
||||
<div class="input-wrapper">
|
||||
<div class="inline-wrapper">
|
||||
<div class="switch-label">
|
||||
<label class="input-label">
|
||||
Show section:
|
||||
</label>
|
||||
<label class="input-label"> Show section: </label>
|
||||
</div>
|
||||
<SwitchInput @input="$updateText('/admin/settings', 'section_features', app.section_features)" v-model="app.section_features" class="switch" :state="app.section_features"/>
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'section_features', app.section_features)"
|
||||
v-model="app.section_features"
|
||||
class="switch"
|
||||
:state="app.section_features"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div v-if="app.section_features">
|
||||
<div class="block-wrapper">
|
||||
<img src="/assets/images/admin/main-features.jpg" alt="Main Features" class="page-image">
|
||||
<img src="/assets/images/admin/main-features.jpg" alt="Main Features" class="page-image" />
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Title:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Title" rules="required" v-slot="{ errors }">
|
||||
<input @input="$updateText('/admin/settings', 'features_title', app.features_title)" v-model="app.features_title" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark"/>
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'features_title', app.features_title)"
|
||||
v-model="app.features_title"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -73,7 +96,13 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Description:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Description" rules="required" v-slot="{ errors }">
|
||||
<textarea @input="$updateText('/admin/settings', 'features_description', app.features_description)" rows="2" v-model="app.features_description" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark"></textarea>
|
||||
<textarea
|
||||
@input="$updateText('/admin/settings', 'features_description', app.features_description)"
|
||||
rows="2"
|
||||
v-model="app.features_description"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
></textarea>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -88,58 +117,97 @@
|
||||
<div class="input-wrapper">
|
||||
<div class="inline-wrapper">
|
||||
<div class="switch-label">
|
||||
<label class="input-label">
|
||||
Show section:
|
||||
</label>
|
||||
<label class="input-label"> Show section: </label>
|
||||
</div>
|
||||
<SwitchInput @input="$updateText('/admin/settings', 'section_feature_boxes', app.section_feature_boxes)" v-model="app.section_feature_boxes" class="switch" :state="app.section_feature_boxes"/>
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'section_feature_boxes', app.section_feature_boxes)"
|
||||
v-model="app.section_feature_boxes"
|
||||
class="switch"
|
||||
:state="app.section_feature_boxes"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="app.section_feature_boxes">
|
||||
<div class="block-wrapper">
|
||||
<img src="/assets/images/admin/feature-boxes.jpg" alt="Main Features" class="page-image">
|
||||
<img src="/assets/images/admin/feature-boxes.jpg" alt="Main Features" class="page-image" />
|
||||
</div>
|
||||
<div class="block-wrapper">
|
||||
<label>First Box Title:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Feature Title 1" rules="required" v-slot="{ errors }">
|
||||
<input @input="$updateText('/admin/settings', 'feature_title_1', app.feature_title_1)" v-model="app.feature_title_1" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark"/>
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'feature_title_1', app.feature_title_1)"
|
||||
v-model="app.feature_title_1"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<div class="block-wrapper">
|
||||
<label>First Box Description:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Feature Description 1" rules="required" v-slot="{ errors }">
|
||||
<textarea @input="$updateText('/admin/settings', 'feature_description_1', app.feature_description_1)" rows="2" v-model="app.feature_description_1" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark"></textarea>
|
||||
<textarea
|
||||
@input="$updateText('/admin/settings', 'feature_description_1', app.feature_description_1)"
|
||||
rows="2"
|
||||
v-model="app.feature_description_1"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
></textarea>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<div class="block-wrapper">
|
||||
<label>Second Box Title:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Feature Title 2" rules="required" v-slot="{ errors }">
|
||||
<input @input="$updateText('/admin/settings', 'feature_title_2', app.feature_title_2)" v-model="app.feature_title_2" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark"/>
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'feature_title_2', app.feature_title_2)"
|
||||
v-model="app.feature_title_2"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<div class="block-wrapper">
|
||||
<label>Second Box Description:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Feature Description 2" rules="required" v-slot="{ errors }">
|
||||
<textarea @input="$updateText('/admin/settings', 'feature_description_2', app.feature_description_2)" rows="2" v-model="app.feature_description_2" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark"></textarea>
|
||||
<textarea
|
||||
@input="$updateText('/admin/settings', 'feature_description_2', app.feature_description_2)"
|
||||
rows="2"
|
||||
v-model="app.feature_description_2"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
></textarea>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<div class="block-wrapper">
|
||||
<label>Third Box Title:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Feature Title 3" rules="required" v-slot="{ errors }">
|
||||
<input @input="$updateText('/admin/settings', 'feature_title_3', app.feature_title_3)" v-model="app.feature_title_3" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark"/>
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'feature_title_3', app.feature_title_3)"
|
||||
v-model="app.feature_title_3"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<div class="block-wrapper">
|
||||
<label>Third Box Description:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Feature Description 3" rules="required" v-slot="{ errors }">
|
||||
<textarea @input="$updateText('/admin/settings', 'feature_description_3', app.feature_description_3)" rows="2" v-model="app.feature_description_3" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark"></textarea>
|
||||
<textarea
|
||||
@input="$updateText('/admin/settings', 'feature_description_3', app.feature_description_3)"
|
||||
rows="2"
|
||||
v-model="app.feature_description_3"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
></textarea>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -154,23 +222,32 @@
|
||||
<div class="input-wrapper">
|
||||
<div class="inline-wrapper">
|
||||
<div class="switch-label">
|
||||
<label class="input-label">
|
||||
Show section:
|
||||
</label>
|
||||
<label class="input-label"> Show section: </label>
|
||||
</div>
|
||||
<SwitchInput @input="$updateText('/admin/settings', 'section_pricing_content', app.section_pricing_content)" v-model="app.section_pricing_content" class="switch" :state="app.section_pricing_content"/>
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'section_pricing_content', app.section_pricing_content)"
|
||||
v-model="app.section_pricing_content"
|
||||
class="switch"
|
||||
:state="app.section_pricing_content"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="app.section_pricing_content">
|
||||
<div class="block-wrapper">
|
||||
<img src="/assets/images/admin/pricing-content.jpg" alt="Main Features" class="page-image">
|
||||
<img src="/assets/images/admin/pricing-content.jpg" alt="Main Features" class="page-image" />
|
||||
</div>
|
||||
<div class="block-wrapper">
|
||||
<label>Title:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Title" rules="required" v-slot="{ errors }">
|
||||
<input @input="$updateText('/admin/settings', 'pricing_title', app.pricing_title)" v-model="app.pricing_title" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark"/>
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'pricing_title', app.pricing_title)"
|
||||
v-model="app.pricing_title"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -178,7 +255,13 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Description:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Description" rules="required" v-slot="{ errors }">
|
||||
<textarea @input="$updateText('/admin/settings', 'pricing_description', app.pricing_description)" rows="2" v-model="app.pricing_description" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark"></textarea>
|
||||
<textarea
|
||||
@input="$updateText('/admin/settings', 'pricing_description', app.pricing_description)"
|
||||
rows="2"
|
||||
v-model="app.pricing_description"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
></textarea>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -193,24 +276,32 @@
|
||||
<div class="input-wrapper">
|
||||
<div class="inline-wrapper">
|
||||
<div class="switch-label">
|
||||
<label class="input-label">
|
||||
Show section:
|
||||
</label>
|
||||
<label class="input-label"> Show section: </label>
|
||||
</div>
|
||||
<SwitchInput @input="$updateText('/admin/settings', 'section_get_started', app.section_get_started)" v-model="app.section_get_started" class="switch" :state="app.section_get_started"/>
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'section_get_started', app.section_get_started)"
|
||||
v-model="app.section_get_started"
|
||||
class="switch"
|
||||
:state="app.section_get_started"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div v-if="app.section_get_started">
|
||||
<div class="block-wrapper">
|
||||
<img src="/assets/images/admin/get-started-content.jpg" alt="Main Features" class="page-image">
|
||||
<img src="/assets/images/admin/get-started-content.jpg" alt="Main Features" class="page-image" />
|
||||
</div>
|
||||
<div class="block-wrapper">
|
||||
<label>Title:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Title" rules="required" v-slot="{ errors }">
|
||||
<input @input="$updateText('/admin/settings', 'get_started_title', app.get_started_title)" v-model="app.get_started_title" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark"/>
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'get_started_title', app.get_started_title)"
|
||||
v-model="app.get_started_title"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -218,7 +309,13 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Description:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Description" rules="required" v-slot="{ errors }">
|
||||
<textarea @input="$updateText('/admin/settings', 'get_started_description', app.get_started_description)" rows="2" v-model="app.get_started_description" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark"></textarea>
|
||||
<textarea
|
||||
@input="$updateText('/admin/settings', 'get_started_description', app.get_started_description)"
|
||||
rows="2"
|
||||
v-model="app.get_started_description"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
></textarea>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -232,7 +329,13 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Footer content:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Title" rules="required" v-slot="{ errors }">
|
||||
<input @input="$updateText('/admin/settings', 'footer_content', app.footer_content)" v-model="app.footer_content" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark"/>
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'footer_content', app.footer_content)"
|
||||
v-model="app.footer_content"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -243,18 +346,18 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AppInputSwitch from "../../../../components/Admin/AppInputSwitch";
|
||||
import AppInputText from "../../../../components/Admin/AppInputText";
|
||||
import AppInputSwitch from '../../../../components/Admin/AppInputSwitch'
|
||||
import AppInputText from '../../../../components/Admin/AppInputText'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import PageTabGroup from "../../../../components/Others/Layout/PageTabGroup";
|
||||
import SelectInput from "../../../../components/Others/Forms/SelectInput";
|
||||
import SwitchInput from "../../../../components/Others/Forms/SwitchInput";
|
||||
import ImageInput from "../../../../components/Others/Forms/ImageInput";
|
||||
import FormLabel from "../../../../components/Others/Forms/FormLabel";
|
||||
import ButtonBase from "../../../../components/FilesView/ButtonBase";
|
||||
import SetupBox from "../../../../components/Others/Forms/SetupBox";
|
||||
import PageTab from "../../../../components/Others/Layout/PageTab";
|
||||
import InfoBox from "../../../../components/Others/Forms/InfoBox";
|
||||
import PageTabGroup from '../../../../components/Others/Layout/PageTabGroup'
|
||||
import SelectInput from '../../../../components/Others/Forms/SelectInput'
|
||||
import SwitchInput from '../../../../components/Others/Forms/SwitchInput'
|
||||
import ImageInput from '../../../../components/Others/Forms/ImageInput'
|
||||
import FormLabel from '../../../../components/Others/Forms/FormLabel'
|
||||
import ButtonBase from '../../../../components/FilesView/ButtonBase'
|
||||
import SetupBox from '../../../../components/Others/Forms/SetupBox'
|
||||
import PageTab from '../../../../components/Others/Layout/PageTab'
|
||||
import InfoBox from '../../../../components/Others/Forms/InfoBox'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import axios from 'axios'
|
||||
import { mapGetters } from 'vuex'
|
||||
@@ -262,8 +365,8 @@ import { mapGetters } from 'vuex'
|
||||
export default {
|
||||
name: 'AppIndex',
|
||||
components: {
|
||||
AppInputSwitch,
|
||||
AppInputText,
|
||||
AppInputSwitch,
|
||||
AppInputText,
|
||||
ValidationObserver,
|
||||
ValidationProvider,
|
||||
PageTabGroup,
|
||||
@@ -275,24 +378,25 @@ export default {
|
||||
SetupBox,
|
||||
required,
|
||||
PageTab,
|
||||
InfoBox
|
||||
InfoBox,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config'])
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
app: undefined
|
||||
app: undefined,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
axios.get('/api/admin/settings', {
|
||||
params: {
|
||||
column: 'allow_homepage|footer_content|get_started_description|get_started_title|pricing_description|pricing_title|feature_description_3|feature_title_3|feature_description_2|feature_title_2|feature_description_1|feature_title_1|features_description|features_title|header_description|header_title|section_get_started|section_pricing_content|section_feature_boxes|section_features'
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
axios
|
||||
.get('/api/admin/settings', {
|
||||
params: {
|
||||
column: 'allow_homepage|footer_content|get_started_description|get_started_title|pricing_description|pricing_title|feature_description_3|feature_title_3|feature_description_2|feature_title_2|feature_description_1|feature_title_1|features_description|features_title|header_description|header_title|section_get_started|section_pricing_content|section_feature_boxes|section_features',
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
this.app = {
|
||||
allow_homepage: parseInt(response.data.allow_homepage),
|
||||
section_features: parseInt(response.data.section_features),
|
||||
@@ -313,13 +417,13 @@ export default {
|
||||
pricing_description: response.data.pricing_description,
|
||||
get_started_title: response.data.get_started_title,
|
||||
get_started_description: response.data.get_started_description,
|
||||
footer_content: response.data.footer_content
|
||||
footer_content: response.data.footer_content,
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,247 +1,291 @@
|
||||
<template>
|
||||
<PageTab :is-loading="isLoading">
|
||||
<!--Store & Upload-->
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Storage & Upload') }}
|
||||
</FormLabel>
|
||||
|
||||
<!--Store & Upload-->
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Storage & Upload') }}
|
||||
</FormLabel>
|
||||
<!--Available only when is not metered billing-->
|
||||
<div v-if="config.subscriptionType !== 'metered'">
|
||||
<AppInputSwitch :title="$t('admin_settings.others.storage_limit')" :description="$t('admin_settings.others.storage_limit_help')">
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'storage_limitation', app.storageLimitation)"
|
||||
v-model="app.storageLimitation"
|
||||
:state="app.storageLimitation"
|
||||
class="switch"
|
||||
/>
|
||||
</AppInputSwitch>
|
||||
|
||||
<!--Available only when is not metered billing-->
|
||||
<div v-if="config.subscriptionType !== 'metered'">
|
||||
<AppInputSwitch :title="$t('admin_settings.others.storage_limit')" :description="$t('admin_settings.others.storage_limit_help')">
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'storage_limitation', app.storageLimitation)"
|
||||
v-model="app.storageLimitation"
|
||||
:state="app.storageLimitation"
|
||||
class="switch"
|
||||
/>
|
||||
</AppInputSwitch>
|
||||
<AppInputText v-if="app.storageLimitation" :title="$t('admin_settings.others.default_storage')">
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'default_max_storage_amount', app.defaultStorage)"
|
||||
v-model="app.defaultStorage"
|
||||
min="1"
|
||||
max="999999999"
|
||||
:placeholder="$t('admin_settings.others.default_storage_plac')"
|
||||
type="number"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
|
||||
<AppInputText v-if="app.storageLimitation" :title="$t('admin_settings.others.default_storage')">
|
||||
<input @input="$updateText('/admin/settings', 'default_max_storage_amount', app.defaultStorage)"
|
||||
v-model="app.defaultStorage"
|
||||
min="1"
|
||||
max="999999999"
|
||||
:placeholder="$t('admin_settings.others.default_storage_plac')"
|
||||
type="number"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
<AppInputText :title="$t('admin_settings.others.upload_limit')" :description="$t('admin_settings.others.upload_limit_help')">
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'upload_limit', app.uploadLimit, true)"
|
||||
v-model="app.uploadLimit"
|
||||
:placeholder="$t('admin_settings.others.upload_limit_plac')"
|
||||
type="number"
|
||||
min="0"
|
||||
step="1"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
|
||||
<AppInputText :title="$t('admin_settings.others.upload_limit')" :description="$t('admin_settings.others.upload_limit_help')">
|
||||
<input @input="$updateText('/admin/settings', 'upload_limit', app.uploadLimit, true)" v-model="app.uploadLimit" :placeholder="$t('admin_settings.others.upload_limit_plac')" type="number" min="0" step="1" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('admin_settings.others.mimetypes_blacklist')" :description="$t('admin_settings.others.mimetypes_blacklist_help')" :is-last="true">
|
||||
<textarea
|
||||
rows="2"
|
||||
@input="$updateText('/admin/settings', 'mimetypes_blacklist', app.mimetypesBlacklist, true)"
|
||||
v-model="app.mimetypesBlacklist"
|
||||
:placeholder="$t('admin_settings.others.mimetypes_blacklist_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
|
||||
<AppInputText :title="$t('admin_settings.others.mimetypes_blacklist')" :description="$t('admin_settings.others.mimetypes_blacklist_help')" :is-last="true">
|
||||
<textarea rows="2" @input="$updateText('/admin/settings', 'mimetypes_blacklist', app.mimetypesBlacklist, true)" v-model="app.mimetypesBlacklist" :placeholder="$t('admin_settings.others.mimetypes_blacklist_plac')" type="text" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</div>
|
||||
<!--Other Settings-->
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Application') }}
|
||||
</FormLabel>
|
||||
|
||||
<!--Other Settings-->
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Application') }}
|
||||
</FormLabel>
|
||||
<AppInputButton :title="$t('Cache')" :description="$t('Did you change anything in your .env file? Then clear your cache.')">
|
||||
<ButtonBase @click.native="flushCache" :loading="isFlushingCache" :disabled="isFlushingCache" class="w-full sm:w-auto" button-style="theme">
|
||||
{{ $t('admin_settings.others.cache_clear') }}
|
||||
</ButtonBase>
|
||||
</AppInputButton>
|
||||
|
||||
<AppInputButton :title="$t('Cache')" :description="$t('Did you change anything in your .env file? Then clear your cache.')">
|
||||
<ButtonBase @click.native="flushCache" :loading="isFlushingCache" :disabled="isFlushingCache" class="sm:w-auto w-full" button-style="theme">
|
||||
{{ $t('admin_settings.others.cache_clear') }}
|
||||
</ButtonBase>
|
||||
</AppInputButton>
|
||||
<AppInputText :title="$t('admin_settings.others.contact_email')">
|
||||
<input
|
||||
class="focus-border-theme input-dark"
|
||||
@input="$updateText('/admin/settings', 'contact_email', app.contactMail)"
|
||||
v-model="app.contactMail"
|
||||
:placeholder="$t('admin_settings.others.contact_email_plac')"
|
||||
type="email"
|
||||
/>
|
||||
</AppInputText>
|
||||
|
||||
<AppInputText :title="$t('admin_settings.others.contact_email')">
|
||||
<input class="focus-border-theme input-dark" @input="$updateText('/admin/settings', 'contact_email', app.contactMail)" v-model="app.contactMail" :placeholder="$t('admin_settings.others.contact_email_plac')" type="email" />
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('admin_settings.others.google_analytics')" :is-last="true">
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'google_analytics', app.googleAnalytics, true)"
|
||||
v-model="app.googleAnalytics"
|
||||
:placeholder="$t('admin_settings.others.google_analytics_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
|
||||
<AppInputText :title="$t('admin_settings.others.google_analytics')" :is-last="true">
|
||||
<input @input="$updateText('/admin/settings', 'google_analytics', app.googleAnalytics, true)" v-model="app.googleAnalytics" :placeholder="$t('admin_settings.others.google_analytics_plac')" type="text" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</div>
|
||||
<!-- ReCaptcha -->
|
||||
<div class="card shadow-card">
|
||||
<FormLabel icon="shield">
|
||||
{{ $t('reCaptcha') }}
|
||||
</FormLabel>
|
||||
|
||||
<!-- ReCaptcha -->
|
||||
<div class="card shadow-card">
|
||||
<FormLabel icon="shield">
|
||||
{{ $t('reCaptcha') }}
|
||||
</FormLabel>
|
||||
<AppInputSwitch
|
||||
:title="$t('Allow ReCaptcha')"
|
||||
:description="$t('ReCaptcha will be allowed on Registration and Contact Us forms.')"
|
||||
:is-last="!recaptcha.allowedService"
|
||||
>
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'allowed_recaptcha', recaptcha.allowedService)"
|
||||
v-model="recaptcha.allowedService"
|
||||
class="switch"
|
||||
:state="recaptcha.allowedService"
|
||||
/>
|
||||
</AppInputSwitch>
|
||||
|
||||
<AppInputSwitch :title="$t('Allow ReCaptcha')" :description="$t('ReCaptcha will be allowed on Registration and Contact Us forms.')" :is-last="! recaptcha.allowedService">
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'allowed_recaptcha', recaptcha.allowedService)"
|
||||
v-model="recaptcha.allowedService"
|
||||
class="switch"
|
||||
:state="recaptcha.allowedService"
|
||||
/>
|
||||
</AppInputSwitch>
|
||||
<div
|
||||
v-if="config.isRecaptchaConfigured && recaptcha.allowedService"
|
||||
@click="recaptcha.isVisibleCredentialsForm = !recaptcha.isVisibleCredentialsForm"
|
||||
class="flex cursor-pointer items-center"
|
||||
:class="{ 'mb-4': recaptcha.isVisibleCredentialsForm }"
|
||||
>
|
||||
<edit2-icon size="12" class="vue-feather text-theme mr-2" />
|
||||
<b class="text-xs">{{ $t('Update Your Credentials') }}</b>
|
||||
</div>
|
||||
|
||||
<div v-if="config.isRecaptchaConfigured && recaptcha.allowedService" @click="recaptcha.isVisibleCredentialsForm = !recaptcha.isVisibleCredentialsForm" class="flex items-center cursor-pointer" :class="{'mb-4': recaptcha.isVisibleCredentialsForm}">
|
||||
<edit2-icon size="12" class="vue-feather text-theme mr-2" />
|
||||
<b class="text-xs">{{ $t('Update Your Credentials') }}</b>
|
||||
</div>
|
||||
<!--Set up recaptcha credentials-->
|
||||
<ValidationObserver
|
||||
v-if="(!config.isRecaptchaConfigured || recaptcha.isVisibleCredentialsForm) && recaptcha.allowedService"
|
||||
@submit.prevent="storeCredentials('recaptcha')"
|
||||
ref="credentialsForm"
|
||||
v-slot="{ invalid }"
|
||||
tag="form"
|
||||
class="rounded-xl p-5 shadow-lg"
|
||||
>
|
||||
<FormLabel v-if="!config.isRecaptchaConfigured" icon="shield">
|
||||
{{ $t('Configure Credentials') }}
|
||||
</FormLabel>
|
||||
|
||||
<!--Set up recaptcha credentials-->
|
||||
<ValidationObserver
|
||||
v-if="(! config.isRecaptchaConfigured || recaptcha.isVisibleCredentialsForm) && recaptcha.allowedService"
|
||||
@submit.prevent="storeCredentials('recaptcha')"
|
||||
ref="credentialsForm"
|
||||
v-slot="{ invalid }"
|
||||
tag="form"
|
||||
class="p-5 shadow-lg rounded-xl"
|
||||
>
|
||||
<FormLabel v-if="! config.isRecaptchaConfigured" icon="shield">
|
||||
{{ $t('Configure Credentials') }}
|
||||
</FormLabel>
|
||||
<ValidationProvider tag="div" mode="passive" name="Site Key" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Site Key')" :error="errors[0]">
|
||||
<input
|
||||
v-model="recaptcha.credentials.client_id"
|
||||
:placeholder="$t('Paste your Site Key here')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<ValidationProvider tag="div" mode="passive" name="Site Key" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Site Key')" :error="errors[0]">
|
||||
<input v-model="recaptcha.credentials.client_id" :placeholder="$t('Paste your Site Key here')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="Secret key" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Secret Key')" :error="errors[0]">
|
||||
<input
|
||||
v-model="recaptcha.credentials.client_secret"
|
||||
:placeholder="$t('Paste your Secret key here')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<ValidationProvider tag="div" mode="passive" name="Secret key" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Secret Key')" :error="errors[0]">
|
||||
<input v-model="recaptcha.credentials.client_secret" :placeholder="$t('Paste your Secret key here')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<ButtonBase :disabled="isLoading" :loading="isLoading" button-style="theme" type="submit" class="w-full">
|
||||
{{ $t('Store Credentials') }}
|
||||
</ButtonBase>
|
||||
</ValidationObserver>
|
||||
|
||||
</div>
|
||||
<ButtonBase :disabled="isLoading" :loading="isLoading" button-style="theme" type="submit" class="w-full">
|
||||
{{ $t('Store Credentials') }}
|
||||
</ButtonBase>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
</PageTab>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
Edit2Icon,
|
||||
} from 'vue-feather-icons'
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import SwitchInput from "../../../../components/Others/Forms/SwitchInput";
|
||||
import AppInputButton from "../../../../components/Admin/AppInputButton"
|
||||
import AppInputSwitch from "../../../../components/Admin/AppInputSwitch"
|
||||
import FormLabel from "../../../../components/Others/Forms/FormLabel";
|
||||
import ButtonBase from "../../../../components/FilesView/ButtonBase";
|
||||
import AppInputText from "../../../../components/Admin/AppInputText"
|
||||
import PageTab from "../../../../components/Others/Layout/PageTab";
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {events} from '../../../../bus'
|
||||
import {mapGetters} from "vuex"
|
||||
import axios from 'axios'
|
||||
import { Edit2Icon } from 'vue-feather-icons'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import SwitchInput from '../../../../components/Others/Forms/SwitchInput'
|
||||
import AppInputButton from '../../../../components/Admin/AppInputButton'
|
||||
import AppInputSwitch from '../../../../components/Admin/AppInputSwitch'
|
||||
import FormLabel from '../../../../components/Others/Forms/FormLabel'
|
||||
import ButtonBase from '../../../../components/FilesView/ButtonBase'
|
||||
import AppInputText from '../../../../components/Admin/AppInputText'
|
||||
import PageTab from '../../../../components/Others/Layout/PageTab'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { events } from '../../../../bus'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'AppOthers',
|
||||
components: {
|
||||
AppInputButton,
|
||||
ValidationObserver,
|
||||
ValidationProvider,
|
||||
AppInputSwitch,
|
||||
AppInputText,
|
||||
SwitchInput,
|
||||
ButtonBase,
|
||||
Edit2Icon,
|
||||
FormLabel,
|
||||
required,
|
||||
PageTab,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config',
|
||||
])
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
isFlushingCache: false,
|
||||
app: undefined,
|
||||
recaptcha: {
|
||||
allowedService: false,
|
||||
isVisibleCredentialsForm: false,
|
||||
credentials: {
|
||||
key: undefined,
|
||||
secret: undefined,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async storeCredentials(service) {
|
||||
export default {
|
||||
name: 'AppOthers',
|
||||
components: {
|
||||
AppInputButton,
|
||||
ValidationObserver,
|
||||
ValidationProvider,
|
||||
AppInputSwitch,
|
||||
AppInputText,
|
||||
SwitchInput,
|
||||
ButtonBase,
|
||||
Edit2Icon,
|
||||
FormLabel,
|
||||
required,
|
||||
PageTab,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
isFlushingCache: false,
|
||||
app: undefined,
|
||||
recaptcha: {
|
||||
allowedService: false,
|
||||
isVisibleCredentialsForm: false,
|
||||
credentials: {
|
||||
key: undefined,
|
||||
secret: undefined,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async storeCredentials(service) {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.credentialsForm.validate()
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.credentialsForm.validate();
|
||||
if (!isValid) return
|
||||
|
||||
if (!isValid) return;
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/admin/settings/social-service', {
|
||||
client_id: this[service].credentials.client_id,
|
||||
client_secret: this[service].credentials.client_secret,
|
||||
service: service,
|
||||
})
|
||||
.then(() => {
|
||||
// Commit credentials
|
||||
this.$store.commit('SET_SOCIAL_LOGIN_CONFIGURED', service)
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/admin/settings/social-service', {
|
||||
client_id: this[service].credentials.client_id,
|
||||
client_secret: this[service].credentials.client_secret,
|
||||
service: service,
|
||||
})
|
||||
.then(() => {
|
||||
// Commit credentials
|
||||
this.$store.commit('SET_SOCIAL_LOGIN_CONFIGURED', service)
|
||||
this[service].allowedService = true
|
||||
this[service].isVisibleCredentialsForm = false
|
||||
|
||||
this[service].allowedService = true
|
||||
this[service].isVisibleCredentialsForm = false
|
||||
// Show toaster
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.credentials_set', {
|
||||
service: service,
|
||||
}),
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response.status === 500) {
|
||||
this.isError = true
|
||||
this.errorMessage = error.response.data.message
|
||||
}
|
||||
})
|
||||
.finally(() => (this.isLoading = false))
|
||||
},
|
||||
flushCache() {
|
||||
this.isFlushingCache = true
|
||||
|
||||
// Show toaster
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.credentials_set', {service: service}),
|
||||
})
|
||||
})
|
||||
.catch(error => {
|
||||
axios
|
||||
.get('/api/admin/settings/flush-cache')
|
||||
.then(() => {
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: 'Your cache was successfully deleted.',
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
this.isFlushingCache = false
|
||||
})
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.recaptcha.allowedService = this.config.allowedRecaptcha
|
||||
|
||||
if (error.response.status === 500) {
|
||||
this.isError = true
|
||||
this.errorMessage = error.response.data.message
|
||||
}
|
||||
})
|
||||
.finally(() => this.isLoading = false)
|
||||
},
|
||||
flushCache() {
|
||||
axios
|
||||
.get('/api/admin/settings', {
|
||||
params: {
|
||||
column: 'contact_email|google_analytics|default_max_storage_amount|storage_limitation|mimetypes_blacklist|upload_limit',
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
this.isLoading = false
|
||||
|
||||
this.isFlushingCache = true
|
||||
|
||||
axios.get('/api/admin/settings/flush-cache')
|
||||
.then(() => {
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: 'Your cache was successfully deleted.',
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
this.isFlushingCache = false
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.recaptcha.allowedService = this.config.allowedRecaptcha
|
||||
|
||||
axios.get('/api/admin/settings', {
|
||||
params: {
|
||||
column: 'contact_email|google_analytics|default_max_storage_amount|storage_limitation|mimetypes_blacklist|upload_limit'
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
this.isLoading = false
|
||||
|
||||
this.app = {
|
||||
contactMail: response.data.contact_email,
|
||||
googleAnalytics: response.data.google_analytics,
|
||||
defaultStorage: response.data.default_max_storage_amount,
|
||||
storageLimitation: parseInt(response.data.storage_limitation),
|
||||
mimetypesBlacklist: response.data.mimetypes_blacklist,
|
||||
uploadLimit: response.data.upload_limit,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
this.app = {
|
||||
contactMail: response.data.contact_email,
|
||||
googleAnalytics: response.data.google_analytics,
|
||||
defaultStorage: response.data.default_max_storage_amount,
|
||||
storageLimitation: parseInt(response.data.storage_limitation),
|
||||
mimetypesBlacklist: response.data.mimetypes_blacklist,
|
||||
uploadLimit: response.data.upload_limit,
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,300 +1,343 @@
|
||||
<template>
|
||||
<PageTab>
|
||||
<!--User Login/Registration-->
|
||||
<div v-if="app" class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('User Login/Registration') }}
|
||||
</FormLabel>
|
||||
|
||||
<!--User Login/Registration-->
|
||||
<div v-if="app" class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('User Login/Registration') }}
|
||||
</FormLabel>
|
||||
<AppInputSwitch :title="$t('admin_settings.others.allow_registration')" :description="$t('admin_settings.others.allow_registration_help')">
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'registration', app.userRegistration)"
|
||||
v-model="app.userRegistration"
|
||||
class="switch"
|
||||
:state="app.userRegistration"
|
||||
/>
|
||||
</AppInputSwitch>
|
||||
|
||||
<AppInputSwitch :title="$t('admin_settings.others.allow_registration')" :description="$t('admin_settings.others.allow_registration_help')">
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'registration', app.userRegistration)"
|
||||
v-model="app.userRegistration"
|
||||
class="switch"
|
||||
:state="app.userRegistration"
|
||||
/>
|
||||
</AppInputSwitch>
|
||||
<AppInputSwitch :title="$t('Require Email Verification')" :description="$t('admin_settings.others.allow_user_verification_help')" :is-last="true">
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'user_verification', app.userVerification)"
|
||||
v-model="app.userVerification"
|
||||
class="switch"
|
||||
:state="app.userVerification"
|
||||
/>
|
||||
</AppInputSwitch>
|
||||
</div>
|
||||
|
||||
<AppInputSwitch :title="$t('Require Email Verification')" :description="$t('admin_settings.others.allow_user_verification_help')" :is-last="true">
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'user_verification', app.userVerification)"
|
||||
v-model="app.userVerification"
|
||||
class="switch"
|
||||
:state="app.userVerification"
|
||||
/>
|
||||
</AppInputSwitch>
|
||||
</div>
|
||||
<!--Facebook Social Authentication-->
|
||||
<div class="card shadow-card">
|
||||
<img :src="$getSocialLogo('facebook')" alt="Facebook" class="mb-8 h-5" />
|
||||
|
||||
<!--Facebook Social Authentication-->
|
||||
<div class="card shadow-card">
|
||||
<img :src="$getSocialLogo('facebook')" alt="Facebook" class="mb-8 h-5">
|
||||
<AppInputSwitch :title="$t('Allow Login via Facebook')" :description="$t('You users will be able to login via Facebook account.')" :is-last="!facebook.allowedService">
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'allowed_facebook_login', facebook.allowedService)"
|
||||
v-model="facebook.allowedService"
|
||||
class="switch"
|
||||
:state="facebook.allowedService"
|
||||
/>
|
||||
</AppInputSwitch>
|
||||
|
||||
<AppInputSwitch :title="$t('Allow Login via Facebook')" :description="$t('You users will be able to login via Facebook account.')" :is-last="! facebook.allowedService">
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'allowed_facebook_login', facebook.allowedService)"
|
||||
v-model="facebook.allowedService"
|
||||
class="switch"
|
||||
:state="facebook.allowedService"
|
||||
/>
|
||||
</AppInputSwitch>
|
||||
<div
|
||||
v-if="config.isFacebookLoginConfigured && facebook.allowedService"
|
||||
@click="facebook.isVisibleCredentialsForm = !facebook.isVisibleCredentialsForm"
|
||||
class="flex cursor-pointer items-center"
|
||||
:class="{ 'mb-4': facebook.isVisibleCredentialsForm }"
|
||||
>
|
||||
<edit2-icon size="12" class="vue-feather text-theme mr-2" />
|
||||
<b class="text-xs">{{ $t('Update Your Credentials') }}</b>
|
||||
</div>
|
||||
|
||||
<div v-if="config.isFacebookLoginConfigured && facebook.allowedService" @click="facebook.isVisibleCredentialsForm = !facebook.isVisibleCredentialsForm" class="flex items-center cursor-pointer" :class="{'mb-4': facebook.isVisibleCredentialsForm}">
|
||||
<edit2-icon size="12" class="vue-feather text-theme mr-2" />
|
||||
<b class="text-xs">{{ $t('Update Your Credentials') }}</b>
|
||||
</div>
|
||||
<!--Set up facebook credentials-->
|
||||
<ValidationObserver
|
||||
v-if="(!config.isFacebookLoginConfigured || facebook.isVisibleCredentialsForm) && facebook.allowedService"
|
||||
@submit.prevent="storeCredentials('facebook_login')"
|
||||
ref="credentialsForm"
|
||||
v-slot="{ invalid }"
|
||||
tag="form"
|
||||
class="rounded-xl p-5 shadow-lg"
|
||||
>
|
||||
<FormLabel v-if="!config.isFacebookLoginConfigured" icon="shield">
|
||||
{{ $t('Configure Credentials') }}
|
||||
</FormLabel>
|
||||
|
||||
<!--Set up facebook credentials-->
|
||||
<ValidationObserver
|
||||
v-if="(! config.isFacebookLoginConfigured || facebook.isVisibleCredentialsForm) && facebook.allowedService"
|
||||
@submit.prevent="storeCredentials('facebook_login')"
|
||||
ref="credentialsForm"
|
||||
v-slot="{ invalid }"
|
||||
tag="form"
|
||||
class="p-5 shadow-lg rounded-xl"
|
||||
>
|
||||
<FormLabel v-if="! config.isFacebookLoginConfigured" icon="shield">
|
||||
{{ $t('Configure Credentials') }}
|
||||
</FormLabel>
|
||||
<ValidationProvider tag="div" mode="passive" name="Client ID" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Client ID')" :error="errors[0]">
|
||||
<input
|
||||
v-model="facebook.credentials.client_id"
|
||||
:placeholder="$t('Paste your Client ID here')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<ValidationProvider tag="div" mode="passive" name="Client ID" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Client ID')" :error="errors[0]">
|
||||
<input v-model="facebook.credentials.client_id" :placeholder="$t('Paste your Client ID here')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="Client Secret" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Client Secret')" :error="errors[0]">
|
||||
<input
|
||||
v-model="facebook.credentials.client_secret"
|
||||
:placeholder="$t('Paste your Client Secret here')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<ValidationProvider tag="div" mode="passive" name="Client Secret" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Client Secret')" :error="errors[0]">
|
||||
<input v-model="facebook.credentials.client_secret" :placeholder="$t('Paste your Client Secret here')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ButtonBase :disabled="isLoading" :loading="isLoading" button-style="theme" type="submit" class="w-full">
|
||||
{{ $t('Store Credentials') }}
|
||||
</ButtonBase>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
|
||||
<ButtonBase :disabled="isLoading" :loading="isLoading" button-style="theme" type="submit" class="w-full">
|
||||
{{ $t('Store Credentials') }}
|
||||
</ButtonBase>
|
||||
</ValidationObserver>
|
||||
<!--Google Social Authentication-->
|
||||
<div class="card shadow-card">
|
||||
<img :src="$getSocialLogo('google')" alt="Google" class="mb-8 h-7" />
|
||||
|
||||
</div>
|
||||
<AppInputSwitch :title="$t('Allow Login via Google')" :description="$t('You users will be able to login via Google account.')" :is-last="!google.allowedService">
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'allowed_google_login', google.allowedService)"
|
||||
v-model="google.allowedService"
|
||||
class="switch"
|
||||
:state="google.allowedService"
|
||||
/>
|
||||
</AppInputSwitch>
|
||||
|
||||
<!--Google Social Authentication-->
|
||||
<div class="card shadow-card">
|
||||
<img :src="$getSocialLogo('google')" alt="Google" class="mb-8 h-7">
|
||||
<div
|
||||
v-if="config.isGoogleLoginConfigured && google.allowedService"
|
||||
@click="google.isVisibleCredentialsForm = !google.isVisibleCredentialsForm"
|
||||
class="flex cursor-pointer items-center"
|
||||
:class="{ 'mb-4': google.isVisibleCredentialsForm }"
|
||||
>
|
||||
<edit2-icon size="12" class="vue-feather text-theme mr-2" />
|
||||
<b class="text-xs">{{ $t('Update Your Credentials') }}</b>
|
||||
</div>
|
||||
|
||||
<AppInputSwitch :title="$t('Allow Login via Google')" :description="$t('You users will be able to login via Google account.')" :is-last="! google.allowedService">
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'allowed_google_login', google.allowedService)"
|
||||
v-model="google.allowedService"
|
||||
class="switch"
|
||||
:state="google.allowedService"
|
||||
/>
|
||||
</AppInputSwitch>
|
||||
<!--Set up Google credentials-->
|
||||
<ValidationObserver
|
||||
v-if="(!config.isGoogleLoginConfigured || google.isVisibleCredentialsForm) && google.allowedService"
|
||||
@submit.prevent="storeCredentials('google_login')"
|
||||
ref="credentialsForm"
|
||||
v-slot="{ invalid }"
|
||||
tag="form"
|
||||
class="rounded-xl p-5 shadow-lg"
|
||||
>
|
||||
<FormLabel v-if="!config.isGoogleLoginConfigured" icon="shield">
|
||||
{{ $t('Configure Credentials') }}
|
||||
</FormLabel>
|
||||
|
||||
<div v-if="config.isGoogleLoginConfigured && google.allowedService" @click="google.isVisibleCredentialsForm = !google.isVisibleCredentialsForm" class="flex items-center cursor-pointer" :class="{'mb-4': google.isVisibleCredentialsForm}">
|
||||
<edit2-icon size="12" class="vue-feather text-theme mr-2" />
|
||||
<b class="text-xs">{{ $t('Update Your Credentials') }}</b>
|
||||
</div>
|
||||
<ValidationProvider tag="div" mode="passive" name="Client ID" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Client ID')" :error="errors[0]">
|
||||
<input
|
||||
v-model="google.credentials.client_id"
|
||||
:placeholder="$t('Paste your Client ID here')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<!--Set up Google credentials-->
|
||||
<ValidationObserver
|
||||
v-if="(! config.isGoogleLoginConfigured || google.isVisibleCredentialsForm) && google.allowedService"
|
||||
@submit.prevent="storeCredentials('google_login')"
|
||||
ref="credentialsForm"
|
||||
v-slot="{ invalid }"
|
||||
tag="form"
|
||||
class="p-5 shadow-lg rounded-xl"
|
||||
>
|
||||
<FormLabel v-if="! config.isGoogleLoginConfigured" icon="shield">
|
||||
{{ $t('Configure Credentials') }}
|
||||
</FormLabel>
|
||||
<ValidationProvider tag="div" mode="passive" name="Client Secret" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Client Secret')" :error="errors[0]">
|
||||
<input
|
||||
v-model="google.credentials.client_secret"
|
||||
:placeholder="$t('Paste your Client Secret here')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<ValidationProvider tag="div" mode="passive" name="Client ID" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Client ID')" :error="errors[0]">
|
||||
<input v-model="google.credentials.client_id" :placeholder="$t('Paste your Client ID here')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ButtonBase :disabled="isLoading" :loading="isLoading" button-style="theme" type="submit" class="w-full">
|
||||
{{ $t('Store Credentials') }}
|
||||
</ButtonBase>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
|
||||
<ValidationProvider tag="div" mode="passive" name="Client Secret" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Client Secret')" :error="errors[0]">
|
||||
<input v-model="google.credentials.client_secret" :placeholder="$t('Paste your Client Secret here')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<!--Github Social Authentication-->
|
||||
<div class="card shadow-card">
|
||||
<img :src="$getSocialLogo('github')" alt="Github" class="mb-8 h-5" />
|
||||
|
||||
<ButtonBase :disabled="isLoading" :loading="isLoading" button-style="theme" type="submit" class="w-full">
|
||||
{{ $t('Store Credentials') }}
|
||||
</ButtonBase>
|
||||
</ValidationObserver>
|
||||
<AppInputSwitch :title="$t('Allow Login via GitHub')" :description="$t('You users will be able to login via GitHub account.')" :is-last="!github.allowedService">
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'allowed_github_login', github.allowedService)"
|
||||
v-model="github.allowedService"
|
||||
class="switch"
|
||||
:state="github.allowedService"
|
||||
/>
|
||||
</AppInputSwitch>
|
||||
|
||||
</div>
|
||||
<div
|
||||
v-if="config.isGithubLoginConfigured && github.allowedService"
|
||||
@click="github.isVisibleCredentialsForm = !github.isVisibleCredentialsForm"
|
||||
class="flex cursor-pointer items-center"
|
||||
:class="{ 'mb-4': github.isVisibleCredentialsForm }"
|
||||
>
|
||||
<edit2-icon size="12" class="vue-feather text-theme mr-2" />
|
||||
<b class="text-xs">{{ $t('Update Your Credentials') }}</b>
|
||||
</div>
|
||||
|
||||
<!--Github Social Authentication-->
|
||||
<div class="card shadow-card">
|
||||
<img :src="$getSocialLogo('github')" alt="Github" class="mb-8 h-5">
|
||||
<!--Set up github credentials-->
|
||||
<ValidationObserver
|
||||
v-if="(!config.isGithubLoginConfigured || github.isVisibleCredentialsForm) && github.allowedService"
|
||||
@submit.prevent="storeCredentials('github_login')"
|
||||
ref="credentialsForm"
|
||||
v-slot="{ invalid }"
|
||||
tag="form"
|
||||
class="rounded-xl p-5 shadow-lg"
|
||||
>
|
||||
<FormLabel v-if="!config.isGithubLoginConfigured" icon="shield">
|
||||
{{ $t('Configure Credentials') }}
|
||||
</FormLabel>
|
||||
|
||||
<AppInputSwitch :title="$t('Allow Login via GitHub')" :description="$t('You users will be able to login via GitHub account.')" :is-last="! github.allowedService">
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'allowed_github_login', github.allowedService)"
|
||||
v-model="github.allowedService"
|
||||
class="switch"
|
||||
:state="github.allowedService"
|
||||
/>
|
||||
</AppInputSwitch>
|
||||
<ValidationProvider tag="div" mode="passive" name="Client ID" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Client ID')" :error="errors[0]">
|
||||
<input
|
||||
v-model="github.credentials.client_id"
|
||||
:placeholder="$t('Paste your Client ID here')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<div v-if="config.isGithubLoginConfigured && github.allowedService" @click="github.isVisibleCredentialsForm = !github.isVisibleCredentialsForm" class="flex items-center cursor-pointer" :class="{'mb-4': github.isVisibleCredentialsForm}">
|
||||
<edit2-icon size="12" class="vue-feather text-theme mr-2" />
|
||||
<b class="text-xs">{{ $t('Update Your Credentials') }}</b>
|
||||
</div>
|
||||
<ValidationProvider tag="div" mode="passive" name="Client Secret" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Client Secret')" :error="errors[0]">
|
||||
<input
|
||||
v-model="github.credentials.client_secret"
|
||||
:placeholder="$t('Paste your Client Secret here')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<!--Set up github credentials-->
|
||||
<ValidationObserver
|
||||
v-if="(! config.isGithubLoginConfigured || github.isVisibleCredentialsForm) && github.allowedService"
|
||||
@submit.prevent="storeCredentials('github_login')"
|
||||
ref="credentialsForm"
|
||||
v-slot="{ invalid }"
|
||||
tag="form"
|
||||
class="p-5 shadow-lg rounded-xl"
|
||||
>
|
||||
<FormLabel v-if="! config.isGithubLoginConfigured" icon="shield">
|
||||
{{ $t('Configure Credentials') }}
|
||||
</FormLabel>
|
||||
|
||||
<ValidationProvider tag="div" mode="passive" name="Client ID" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Client ID')" :error="errors[0]">
|
||||
<input v-model="github.credentials.client_id" :placeholder="$t('Paste your Client ID here')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<ValidationProvider tag="div" mode="passive" name="Client Secret" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Client Secret')" :error="errors[0]">
|
||||
<input v-model="github.credentials.client_secret" :placeholder="$t('Paste your Client Secret here')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<ButtonBase :disabled="isLoading" :loading="isLoading" button-style="theme" type="submit" class="w-full">
|
||||
{{ $t('Store Credentials') }}
|
||||
</ButtonBase>
|
||||
</ValidationObserver>
|
||||
|
||||
</div>
|
||||
<ButtonBase :disabled="isLoading" :loading="isLoading" button-style="theme" type="submit" class="w-full">
|
||||
{{ $t('Store Credentials') }}
|
||||
</ButtonBase>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
</PageTab>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
Edit2Icon,
|
||||
} from 'vue-feather-icons'
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import SwitchInput from "../../../../components/Others/Forms/SwitchInput";
|
||||
import AppInputSwitch from "../../../../components/Admin/AppInputSwitch"
|
||||
import FormLabel from "../../../../components/Others/Forms/FormLabel";
|
||||
import ButtonBase from "../../../../components/FilesView/ButtonBase";
|
||||
import AppInputText from "../../../../components/Admin/AppInputText"
|
||||
import PageTab from "../../../../components/Others/Layout/PageTab";
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {events} from '../../../../bus'
|
||||
import {mapGetters} from "vuex"
|
||||
import axios from 'axios'
|
||||
import { Edit2Icon } from 'vue-feather-icons'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import SwitchInput from '../../../../components/Others/Forms/SwitchInput'
|
||||
import AppInputSwitch from '../../../../components/Admin/AppInputSwitch'
|
||||
import FormLabel from '../../../../components/Others/Forms/FormLabel'
|
||||
import ButtonBase from '../../../../components/FilesView/ButtonBase'
|
||||
import AppInputText from '../../../../components/Admin/AppInputText'
|
||||
import PageTab from '../../../../components/Others/Layout/PageTab'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { events } from '../../../../bus'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'SignInUp',
|
||||
components: {
|
||||
ValidationObserver,
|
||||
ValidationProvider,
|
||||
AppInputSwitch,
|
||||
AppInputText,
|
||||
SwitchInput,
|
||||
ButtonBase,
|
||||
Edit2Icon,
|
||||
FormLabel,
|
||||
required,
|
||||
PageTab,
|
||||
events,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config',
|
||||
])
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
app: {
|
||||
userRegistration: undefined,
|
||||
userVerification: undefined,
|
||||
},
|
||||
facebook: {
|
||||
allowedService: false,
|
||||
isVisibleCredentialsForm: false,
|
||||
credentials: {
|
||||
key: undefined,
|
||||
secret: undefined,
|
||||
},
|
||||
},
|
||||
google: {
|
||||
allowedService: false,
|
||||
isVisibleCredentialsForm: false,
|
||||
credentials: {
|
||||
key: undefined,
|
||||
secret: undefined,
|
||||
},
|
||||
},
|
||||
github: {
|
||||
allowedService: false,
|
||||
isVisibleCredentialsForm: false,
|
||||
credentials: {
|
||||
key: undefined,
|
||||
secret: undefined,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async storeCredentials(service) {
|
||||
export default {
|
||||
name: 'SignInUp',
|
||||
components: {
|
||||
ValidationObserver,
|
||||
ValidationProvider,
|
||||
AppInputSwitch,
|
||||
AppInputText,
|
||||
SwitchInput,
|
||||
ButtonBase,
|
||||
Edit2Icon,
|
||||
FormLabel,
|
||||
required,
|
||||
PageTab,
|
||||
events,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
app: {
|
||||
userRegistration: undefined,
|
||||
userVerification: undefined,
|
||||
},
|
||||
facebook: {
|
||||
allowedService: false,
|
||||
isVisibleCredentialsForm: false,
|
||||
credentials: {
|
||||
key: undefined,
|
||||
secret: undefined,
|
||||
},
|
||||
},
|
||||
google: {
|
||||
allowedService: false,
|
||||
isVisibleCredentialsForm: false,
|
||||
credentials: {
|
||||
key: undefined,
|
||||
secret: undefined,
|
||||
},
|
||||
},
|
||||
github: {
|
||||
allowedService: false,
|
||||
isVisibleCredentialsForm: false,
|
||||
credentials: {
|
||||
key: undefined,
|
||||
secret: undefined,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async storeCredentials(service) {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.credentialsForm.validate()
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.credentialsForm.validate();
|
||||
if (!isValid) return
|
||||
|
||||
if (!isValid) return;
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/admin/settings/social-service', {
|
||||
client_id: this[service].credentials.client_id,
|
||||
client_secret: this[service].credentials.client_secret,
|
||||
service: service,
|
||||
})
|
||||
.then(() => {
|
||||
// Commit credentials
|
||||
this.$store.commit('SET_SOCIAL_LOGIN_CONFIGURED', service)
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/admin/settings/social-service', {
|
||||
client_id: this[service].credentials.client_id,
|
||||
client_secret: this[service].credentials.client_secret,
|
||||
service: service,
|
||||
})
|
||||
.then(() => {
|
||||
// Commit credentials
|
||||
this.$store.commit('SET_SOCIAL_LOGIN_CONFIGURED', service)
|
||||
this[service].allowedService = true
|
||||
this[service].isVisibleCredentialsForm = false
|
||||
|
||||
this[service].allowedService = true
|
||||
this[service].isVisibleCredentialsForm = false
|
||||
// Show toaster
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.credentials_set', {
|
||||
service: service,
|
||||
}),
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response.status === 500) {
|
||||
this.isError = true
|
||||
this.errorMessage = error.response.data.message
|
||||
}
|
||||
})
|
||||
.finally(() => (this.isLoading = false))
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.facebook.allowedService = this.config.allowedFacebookLogin
|
||||
this.google.allowedService = this.config.allowedGoogleLogin
|
||||
this.github.allowedService = this.config.allowedGithubLogin
|
||||
|
||||
// Show toaster
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.credentials_set', {service: service}),
|
||||
})
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
if (error.response.status === 500) {
|
||||
this.isError = true
|
||||
this.errorMessage = error.response.data.message
|
||||
}
|
||||
})
|
||||
.finally(() => this.isLoading = false)
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.facebook.allowedService = this.config.allowedFacebookLogin
|
||||
this.google.allowedService = this.config.allowedGoogleLogin
|
||||
this.github.allowedService = this.config.allowedGithubLogin
|
||||
|
||||
this.app.userRegistration = this.config.userRegistration
|
||||
this.app.userVerification = this.config.userVerification
|
||||
}
|
||||
}
|
||||
this.app.userRegistration = this.config.userRegistration
|
||||
this.app.userVerification = this.config.userVerification
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,145 +1,139 @@
|
||||
<template>
|
||||
<div id="single-page">
|
||||
<div id="page-content" v-if="! isLoading && data">
|
||||
<div id="page-content" v-if="!isLoading && data">
|
||||
<!--Headline-->
|
||||
<div v-if="config.isAdminVueFileManagerBar" class="mb-4 hidden justify-between md:mb-6 md:block md:flex">
|
||||
<!--VueFileManager logo-->
|
||||
<a href="https://vuefilemanager.com" target="_blank">
|
||||
<img src="/assets/images/vuefilemanager-horizontal-logo.svg" alt="VueFileManager" class="light-mode" />
|
||||
</a>
|
||||
|
||||
<!--Headline-->
|
||||
<div v-if="config.isAdminVueFileManagerBar" class="md:flex justify-between md:mb-6 mb-4 md:block hidden">
|
||||
|
||||
<!--VueFileManager logo-->
|
||||
<a href="https://vuefilemanager.com" target="_blank">
|
||||
<img src="/assets/images/vuefilemanager-horizontal-logo.svg" alt="VueFileManager" class="light-mode">
|
||||
</a>
|
||||
|
||||
<!--App Info-->
|
||||
<div class="flex items-center md:mt-0 mt-4">
|
||||
<a href="https://gist.github.com/MakingCG/9c07f8af392081ae5d5290d920a79b5d" target="_blank" class="inline-block mr-4">
|
||||
<span class="font-bold text-sm">
|
||||
{{ $t('admin_page_dashboard.version') }}:
|
||||
</span>
|
||||
<!--App Info-->
|
||||
<div class="mt-4 flex items-center md:mt-0">
|
||||
<a href="https://gist.github.com/MakingCG/9c07f8af392081ae5d5290d920a79b5d" target="_blank" class="mr-4 inline-block">
|
||||
<span class="text-sm font-bold"> {{ $t('admin_page_dashboard.version') }}: </span>
|
||||
<ColorLabel color="purple">
|
||||
{{ data.app.version }}
|
||||
</ColorLabel>
|
||||
</a>
|
||||
<a href="https://codecanyon.net/item/vue-file-manager-with-laravel-backend/25815986" target="_blank" class="inline-block mr-4">
|
||||
<span class="font-bold text-sm">
|
||||
{{ $t('admin_page_dashboard.license') }}:
|
||||
</span>
|
||||
<a href="https://codecanyon.net/item/vue-file-manager-with-laravel-backend/25815986" target="_blank" class="mr-4 inline-block">
|
||||
<span class="text-sm font-bold"> {{ $t('admin_page_dashboard.license') }}: </span>
|
||||
<ColorLabel color="purple">
|
||||
{{ data.app.license }}
|
||||
</ColorLabel>
|
||||
</a>
|
||||
<a href="https://bit.ly/VueFileManager-survey" target="_blank" class="items-center inline-block rounded-lg py-1.5 px-3 ml-8 bg-theme-100 md:flex hidden">
|
||||
<thumbs-up-icon size="15" class="vue-feather text-theme mr-2.5"/>
|
||||
<span class="font-bold text-sm text-theme">
|
||||
<a href="https://bit.ly/VueFileManager-survey" target="_blank" class="bg-theme-100 ml-8 inline-block hidden items-center rounded-lg py-1.5 px-3 md:flex">
|
||||
<thumbs-up-icon size="15" class="vue-feather text-theme mr-2.5" />
|
||||
<span class="text-theme text-sm font-bold">
|
||||
{{ $t('Write a Feedback') }}
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Metric widgets-->
|
||||
<div class="md:flex md:space-x-6 md:mb-6 mb-2">
|
||||
<div class="w-full md:mb-0 mb-4 card shadow-card">
|
||||
<FormLabel icon="users">
|
||||
{{ $t('Total Users') }}
|
||||
</FormLabel>
|
||||
<!--Metric widgets-->
|
||||
<div class="mb-2 md:mb-6 md:flex md:space-x-6">
|
||||
<div class="card mb-4 w-full shadow-card md:mb-0">
|
||||
<FormLabel icon="users">
|
||||
{{ $t('Total Users') }}
|
||||
</FormLabel>
|
||||
|
||||
<b class="sm:text-3xl text-2xl font-extrabold -mt-3 block mb-0.5">
|
||||
{{ data.users.total }}
|
||||
</b>
|
||||
<b class="-mt-3 mb-0.5 block text-2xl font-extrabold sm:text-3xl">
|
||||
{{ data.users.total }}
|
||||
</b>
|
||||
|
||||
<router-link :to="{name: 'Users'}" class="flex items-center mt-6">
|
||||
<span class="text-xs font-bold mr-2 whitespace-nowrap">
|
||||
{{ $t('admin_page_dashboard.w_total_space.link') }}
|
||||
</span>
|
||||
<chevron-right-icon size="16" class="text-theme vue-feather"/>
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="w-full md:mb-0 mb-4 card shadow-card">
|
||||
<FormLabel icon="hard-drive">
|
||||
{{ $t('Total Storage') }}
|
||||
</FormLabel>
|
||||
<router-link :to="{ name: 'Users' }" class="mt-6 flex items-center">
|
||||
<span class="mr-2 whitespace-nowrap text-xs font-bold">
|
||||
{{ $t('admin_page_dashboard.w_total_space.link') }}
|
||||
</span>
|
||||
<chevron-right-icon size="16" class="text-theme vue-feather" />
|
||||
</router-link>
|
||||
</div>
|
||||
<div class="card mb-4 w-full shadow-card md:mb-0">
|
||||
<FormLabel icon="hard-drive">
|
||||
{{ $t('Total Storage') }}
|
||||
</FormLabel>
|
||||
|
||||
<b class="sm:text-3xl text-2xl font-extrabold -mt-3 block mb-0.5">
|
||||
{{ data.disk.used }}
|
||||
</b>
|
||||
<b class="-mt-3 mb-0.5 block text-2xl font-extrabold sm:text-3xl">
|
||||
{{ data.disk.used }}
|
||||
</b>
|
||||
|
||||
<router-link :to="{name: 'Users'}" class="flex items-center mt-6">
|
||||
<span class="text-xs font-bold mr-2 whitespace-nowrap">
|
||||
{{ $t('admin_page_dashboard.w_total_space.link') }}
|
||||
</span>
|
||||
<chevron-right-icon size="16" class="text-theme vue-feather"/>
|
||||
</router-link>
|
||||
</div>
|
||||
<div v-if="config.subscriptionType !== 'none'" class="w-full md:mb-0 mb-4 card shadow-card">
|
||||
<FormLabel icon="dollar">
|
||||
{{ $t('Earnings') }}
|
||||
</FormLabel>
|
||||
<router-link :to="{ name: 'Users' }" class="mt-6 flex items-center">
|
||||
<span class="mr-2 whitespace-nowrap text-xs font-bold">
|
||||
{{ $t('admin_page_dashboard.w_total_space.link') }}
|
||||
</span>
|
||||
<chevron-right-icon size="16" class="text-theme vue-feather" />
|
||||
</router-link>
|
||||
</div>
|
||||
<div v-if="config.subscriptionType !== 'none'" class="card mb-4 w-full shadow-card md:mb-0">
|
||||
<FormLabel icon="dollar">
|
||||
{{ $t('Earnings') }}
|
||||
</FormLabel>
|
||||
|
||||
<b class="sm:text-3xl text-2xl font-extrabold -mt-3 block mb-0.5">
|
||||
{{ data.app.earnings }}
|
||||
</b>
|
||||
<b class="-mt-3 mb-0.5 block text-2xl font-extrabold sm:text-3xl">
|
||||
{{ data.app.earnings }}
|
||||
</b>
|
||||
|
||||
<router-link :to="{name: 'Invoices'}" class="flex items-center mt-6">
|
||||
<span class="text-xs font-bold mr-2 whitespace-nowrap">
|
||||
{{ $t('Show all transactions') }}
|
||||
</span>
|
||||
<chevron-right-icon size="16" class="text-theme vue-feather"/>
|
||||
</router-link>
|
||||
</div>
|
||||
<router-link :to="{ name: 'Invoices' }" class="mt-6 flex items-center">
|
||||
<span class="mr-2 whitespace-nowrap text-xs font-bold">
|
||||
{{ $t('Show all transactions') }}
|
||||
</span>
|
||||
<chevron-right-icon size="16" class="text-theme vue-feather" />
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Upload bandwidth widgets-->
|
||||
<div class="card shadow-card md:mb-6 mb-4">
|
||||
<FormLabel icon="hard-drive">
|
||||
{{ $t('Upload') }}
|
||||
</FormLabel>
|
||||
<!--Upload bandwidth widgets-->
|
||||
<div class="card mb-4 shadow-card md:mb-6">
|
||||
<FormLabel icon="hard-drive">
|
||||
{{ $t('Upload') }}
|
||||
</FormLabel>
|
||||
|
||||
<b class="sm:text-3xl text-2xl font-extrabold -mt-3 block mb-0.5">
|
||||
{{ data.disk.upload.total }}
|
||||
</b>
|
||||
<b class="-mt-3 mb-0.5 block text-2xl font-extrabold sm:text-3xl">
|
||||
{{ data.disk.upload.total }}
|
||||
</b>
|
||||
|
||||
<b class="mb-3 block text-sm text-gray-400 mb-2">
|
||||
{{ $t('In last 45 days') }}
|
||||
</b>
|
||||
<b class="mb-3 mb-2 block text-sm text-gray-400">
|
||||
{{ $t('In last 45 days') }}
|
||||
</b>
|
||||
|
||||
<BarChart :data="data.disk.upload.records" />
|
||||
</div>
|
||||
<BarChart :data="data.disk.upload.records" />
|
||||
</div>
|
||||
|
||||
<!--Download bandwidth widgets-->
|
||||
<div class="card shadow-card md:mb-6 mb-4">
|
||||
<FormLabel icon="hard-drive">
|
||||
{{ $t('Download') }}
|
||||
</FormLabel>
|
||||
<!--Download bandwidth widgets-->
|
||||
<div class="card mb-4 shadow-card md:mb-6">
|
||||
<FormLabel icon="hard-drive">
|
||||
{{ $t('Download') }}
|
||||
</FormLabel>
|
||||
|
||||
<b class="sm:text-3xl text-2xl font-extrabold -mt-3 block mb-0.5">
|
||||
{{ data.disk.download.total }}
|
||||
</b>
|
||||
<b class="-mt-3 mb-0.5 block text-2xl font-extrabold sm:text-3xl">
|
||||
{{ data.disk.download.total }}
|
||||
</b>
|
||||
|
||||
<b class="mb-3 block text-sm text-gray-400 mb-5">
|
||||
{{ $t('In last 45 days') }}
|
||||
</b>
|
||||
<b class="mb-3 mb-5 block text-sm text-gray-400">
|
||||
{{ $t('In last 45 days') }}
|
||||
</b>
|
||||
|
||||
<BarChart :data="data.disk.download.records" />
|
||||
</div>
|
||||
<BarChart :data="data.disk.download.records" />
|
||||
</div>
|
||||
|
||||
<!--Latest registration widgets-->
|
||||
<div class="card shadow-card md:mb-6 mb-4">
|
||||
<FormLabel icon="users">
|
||||
{{ $t('Latest Registrations') }}
|
||||
</FormLabel>
|
||||
<!--Latest registration widgets-->
|
||||
<div class="card mb-4 shadow-card md:mb-6">
|
||||
<FormLabel icon="users">
|
||||
{{ $t('Latest Registrations') }}
|
||||
</FormLabel>
|
||||
|
||||
<WidgetLatestRegistrations />
|
||||
</div>
|
||||
<WidgetLatestRegistrations />
|
||||
</div>
|
||||
|
||||
<!--Latest transactions widgets-->
|
||||
<div v-if="['fixed', 'metered'].includes(this.config.subscriptionType)" class="card shadow-card md:mb-6 mb-4">
|
||||
<FormLabel icon="dollar">
|
||||
{{ $t('Latest Transactions') }}
|
||||
</FormLabel>
|
||||
<!--Latest transactions widgets-->
|
||||
<div v-if="['fixed', 'metered'].includes(this.config.subscriptionType)" class="card mb-4 shadow-card md:mb-6">
|
||||
<FormLabel icon="dollar">
|
||||
{{ $t('Latest Transactions') }}
|
||||
</FormLabel>
|
||||
|
||||
<WidgetLatestTransactions />
|
||||
</div>
|
||||
<WidgetLatestTransactions />
|
||||
</div>
|
||||
</div>
|
||||
<div id="loader" v-if="isLoading">
|
||||
<Spinner></Spinner>
|
||||
@@ -148,49 +142,48 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import WidgetLatestRegistrations from "../../components/Admin/WidgetLatestRegistrations";
|
||||
import ColorLabel from "../../components/Others/ColorLabel";
|
||||
import {ChevronRightIcon, ThumbsUpIcon} from "vue-feather-icons"
|
||||
import WidgetWrapper from "../../components/Admin/WidgetWrapper"
|
||||
import Spinner from "../../components/FilesView/Spinner";
|
||||
import FormLabel from "../../components/Others/Forms/FormLabel"
|
||||
import BarChart from "../../components/UI/BarChart"
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
import WidgetLatestTransactions from "../../components/Admin/WidgetLatestTransactions";
|
||||
import WidgetLatestRegistrations from '../../components/Admin/WidgetLatestRegistrations'
|
||||
import ColorLabel from '../../components/Others/ColorLabel'
|
||||
import { ChevronRightIcon, ThumbsUpIcon } from 'vue-feather-icons'
|
||||
import WidgetWrapper from '../../components/Admin/WidgetWrapper'
|
||||
import Spinner from '../../components/FilesView/Spinner'
|
||||
import FormLabel from '../../components/Others/Forms/FormLabel'
|
||||
import BarChart from '../../components/UI/BarChart'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
import WidgetLatestTransactions from '../../components/Admin/WidgetLatestTransactions'
|
||||
|
||||
export default {
|
||||
name: 'Dashboard',
|
||||
components: {
|
||||
WidgetLatestTransactions,
|
||||
WidgetLatestRegistrations,
|
||||
ChevronRightIcon,
|
||||
WidgetWrapper,
|
||||
ThumbsUpIcon,
|
||||
ColorLabel,
|
||||
FormLabel,
|
||||
BarChart,
|
||||
Spinner,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config'
|
||||
]),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
data: undefined,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
axios.get('/api/admin/dashboard')
|
||||
.then(response => {
|
||||
this.data = response.data
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
export default {
|
||||
name: 'Dashboard',
|
||||
components: {
|
||||
WidgetLatestTransactions,
|
||||
WidgetLatestRegistrations,
|
||||
ChevronRightIcon,
|
||||
WidgetWrapper,
|
||||
ThumbsUpIcon,
|
||||
ColorLabel,
|
||||
FormLabel,
|
||||
BarChart,
|
||||
Spinner,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
data: undefined,
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
axios
|
||||
.get('/api/admin/dashboard')
|
||||
.then((response) => {
|
||||
this.data = response.data
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,81 +1,72 @@
|
||||
<template>
|
||||
<div>
|
||||
<!--Datatable-->
|
||||
<DatatableWrapper
|
||||
v-if="! config.isEmptyTransactions" class="card shadow-card overflow-x-auto"
|
||||
api="/api/admin/transactions"
|
||||
:paginator="true"
|
||||
:columns="columns"
|
||||
>
|
||||
<template slot-scope="{ row }">
|
||||
<!--Transaction rows-->
|
||||
<MeteredTransactionRow v-if="config.subscriptionType === 'metered'" :row="row" :user="true" @showDetail="showTransactionDetail" />
|
||||
<!--Datatable-->
|
||||
<DatatableWrapper v-if="!config.isEmptyTransactions" class="card overflow-x-auto shadow-card" api="/api/admin/transactions" :paginator="true" :columns="columns">
|
||||
<template slot-scope="{ row }">
|
||||
<!--Transaction rows-->
|
||||
<MeteredTransactionRow v-if="config.subscriptionType === 'metered'" :row="row" :user="true" @showDetail="showTransactionDetail" />
|
||||
|
||||
<FixedTransactionRow v-if="config.subscriptionType === 'fixed'" :row="row" :user="true" />
|
||||
<FixedTransactionRow v-if="config.subscriptionType === 'fixed'" :row="row" :user="true" />
|
||||
|
||||
<!--Transaction detail-->
|
||||
<MeteredTransactionDetailRow v-if="row.data.attributes.metadata && showedTransactionDetailById === row.data.id" :row="row" />
|
||||
</template>
|
||||
</DatatableWrapper>
|
||||
<!--Transaction detail-->
|
||||
<MeteredTransactionDetailRow v-if="row.data.attributes.metadata && showedTransactionDetailById === row.data.id" :row="row" />
|
||||
</template>
|
||||
</DatatableWrapper>
|
||||
|
||||
<!--Empty State-->
|
||||
<div v-if="config.isEmptyTransactions" class="flex items-center justify-center h-full">
|
||||
<div class="text-center">
|
||||
<img class="w-28 inline-block mb-6" src="https://twemoji.maxcdn.com/v/13.1.0/svg/1f9ee.svg" alt="transaction">
|
||||
<h1 class="text-2xl font-bold mb-1">
|
||||
{{ $t("There is Nothing") }}
|
||||
</h1>
|
||||
<p class="text-sm text-gray-600">
|
||||
{{ $t('All your transactions will be visible here') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<!--Empty State-->
|
||||
<div v-if="config.isEmptyTransactions" class="flex h-full items-center justify-center">
|
||||
<div class="text-center">
|
||||
<img class="mb-6 inline-block w-28" src="https://twemoji.maxcdn.com/v/13.1.0/svg/1f9ee.svg" alt="transaction" />
|
||||
<h1 class="mb-1 text-2xl font-bold">
|
||||
{{ $t('There is Nothing') }}
|
||||
</h1>
|
||||
<p class="text-sm text-gray-600">
|
||||
{{ $t('All your transactions will be visible here') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FixedTransactionRow from "../../components/Subscription/FixedTransactionRow";
|
||||
import MeteredTransactionDetailRow from "../../components/Subscription/MeteredTransactionDetailRow";
|
||||
import MeteredTransactionRow from "../../components/Subscription/MeteredTransactionRow";
|
||||
import MemberAvatar from "../../components/FilesView/MemberAvatar"
|
||||
import DatatableWrapper from "../../components/Others/Tables/DatatableWrapper";
|
||||
import ColorLabel from "../../components/Others/ColorLabel";
|
||||
import {mapGetters} from 'vuex'
|
||||
import FixedTransactionRow from '../../components/Subscription/FixedTransactionRow'
|
||||
import MeteredTransactionDetailRow from '../../components/Subscription/MeteredTransactionDetailRow'
|
||||
import MeteredTransactionRow from '../../components/Subscription/MeteredTransactionRow'
|
||||
import MemberAvatar from '../../components/FilesView/MemberAvatar'
|
||||
import DatatableWrapper from '../../components/Others/Tables/DatatableWrapper'
|
||||
import ColorLabel from '../../components/Others/ColorLabel'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Invoices',
|
||||
components: {
|
||||
MeteredTransactionDetailRow,
|
||||
MeteredTransactionRow,
|
||||
FixedTransactionRow,
|
||||
DatatableWrapper,
|
||||
MemberAvatar,
|
||||
ColorLabel,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config',
|
||||
]),
|
||||
columns() {
|
||||
if (config.subscriptionType === 'fixed') {
|
||||
return this.$store.getters.transactionColumns.filter(column => ! ['type'].includes(column.field))
|
||||
}
|
||||
export default {
|
||||
name: 'Invoices',
|
||||
components: {
|
||||
MeteredTransactionDetailRow,
|
||||
MeteredTransactionRow,
|
||||
FixedTransactionRow,
|
||||
DatatableWrapper,
|
||||
MemberAvatar,
|
||||
ColorLabel,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
columns() {
|
||||
if (config.subscriptionType === 'fixed') {
|
||||
return this.$store.getters.transactionColumns.filter((column) => !['type'].includes(column.field))
|
||||
}
|
||||
|
||||
return this.$store.getters.transactionColumns
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showedTransactionDetailById: undefined
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showTransactionDetail(id) {
|
||||
if (this.showedTransactionDetailById === id)
|
||||
this.showedTransactionDetailById = undefined
|
||||
else
|
||||
this.showedTransactionDetailById = id
|
||||
}
|
||||
}
|
||||
}
|
||||
return this.$store.getters.transactionColumns
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showedTransactionDetailById: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showTransactionDetail(id) {
|
||||
if (this.showedTransactionDetailById === id) this.showedTransactionDetailById = undefined
|
||||
else this.showedTransactionDetailById = id
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,269 +1,287 @@
|
||||
<template>
|
||||
<div>
|
||||
<!--Mobile language navigation-->
|
||||
<div v-if="languages" id="card-navigation" style="height: 62px" class="md:hidden block mb-24">
|
||||
<div
|
||||
class="bg-white z-20 sm:pt-5 pt-3"
|
||||
:class="{
|
||||
'fixed top-0 left-0 right-0 px-6 rounded-none backdrop-filter backdrop-blur-lg dark:bg-dark-foreground bg-white bg-opacity-70 z-10': fixedNav,
|
||||
'card shadow-card py-0 sticky top-0 z-10 md:hidden block': ! fixedNav
|
||||
}"
|
||||
>
|
||||
<SearchInput v-model="query" @reset-query="query = ''"/>
|
||||
<div>
|
||||
<!--Mobile language navigation-->
|
||||
<div v-if="languages" id="card-navigation" style="height: 62px" class="mb-24 block md:hidden">
|
||||
<div
|
||||
class="z-20 bg-white pt-3 sm:pt-5"
|
||||
:class="{
|
||||
'fixed top-0 left-0 right-0 z-10 rounded-none bg-white bg-opacity-70 px-6 backdrop-blur-lg backdrop-filter dark:bg-dark-foreground': fixedNav,
|
||||
'card sticky top-0 z-10 block py-0 shadow-card md:hidden': !fixedNav,
|
||||
}"
|
||||
>
|
||||
<SearchInput v-model="query" @reset-query="query = ''" />
|
||||
|
||||
<div class="flex items-center">
|
||||
<!--List of languages-->
|
||||
<div
|
||||
@click="getLanguage(language)"
|
||||
v-for="language in languages"
|
||||
:key="language.data.id"
|
||||
class="inline-block text-sm font-bold px-4 py-5 border-b-2 border-transparent border-bottom-theme"
|
||||
:class="{'text-theme router-link-active': selectedLanguage && selectedLanguage.data.attributes.locale === language.data.attributes.locale, 'text-gray-600': !selectedLanguage && selectedLanguage.data.attributes.locale !== language.data.attributes.locale}"
|
||||
>
|
||||
{{ language.data.attributes.name }}
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<!--List of languages-->
|
||||
<div
|
||||
@click="getLanguage(language)"
|
||||
v-for="language in languages"
|
||||
:key="language.data.id"
|
||||
class="border-bottom-theme inline-block border-b-2 border-transparent px-4 py-5 text-sm font-bold"
|
||||
:class="{
|
||||
'text-theme router-link-active': selectedLanguage && selectedLanguage.data.attributes.locale === language.data.attributes.locale,
|
||||
'text-gray-600': !selectedLanguage && selectedLanguage.data.attributes.locale !== language.data.attributes.locale,
|
||||
}"
|
||||
>
|
||||
{{ language.data.attributes.name }}
|
||||
</div>
|
||||
|
||||
<!--Add new language-->
|
||||
<div @click="createLanguage" class="ml-2 cursor-pointer">
|
||||
<plus-icon size="14" class="vue-feather text-gray-400"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--Add new language-->
|
||||
<div @click="createLanguage" class="ml-2 cursor-pointer">
|
||||
<plus-icon size="14" class="vue-feather text-gray-400" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div v-if="languages" class="flex md:space-x-6">
|
||||
<!--Sidebar-->
|
||||
<div class="hidden md:block">
|
||||
<div class="card sticky top-0 shadow-card">
|
||||
<label class="mb-2 text-xs font-bold text-gray-400">
|
||||
{{ $t('languages') }}
|
||||
</label>
|
||||
|
||||
<div v-if="languages" class="flex md:space-x-6">
|
||||
<!-- Languages -->
|
||||
<div
|
||||
@click="getLanguage(language)"
|
||||
v-for="language in languages"
|
||||
:key="language.data.id"
|
||||
class="group flex cursor-pointer items-center justify-between py-2 pr-4"
|
||||
>
|
||||
<label
|
||||
class="text-base font-bold"
|
||||
:class="{
|
||||
'text-theme': selectedLanguage && selectedLanguage.data.attributes.locale === language.data.attributes.locale,
|
||||
}"
|
||||
>
|
||||
{{ language.data.attributes.name }}
|
||||
</label>
|
||||
<x-icon v-if="language.data.attributes.locale !== 'en'" @click.stop="deleteLanguage(language)" class="opacity-0 group-hover:opacity-100" size="12" />
|
||||
</div>
|
||||
|
||||
<!--Sidebar-->
|
||||
<div class="md:block hidden">
|
||||
<div class="card shadow-card sticky top-0">
|
||||
<label class="mb-2 text-xs text-gray-400 font-bold">
|
||||
{{ $t('languages') }}
|
||||
</label>
|
||||
<!-- Create Language button -->
|
||||
<MobileActionButton @click.native="createLanguage" icon="plus" class="mt-5 whitespace-nowrap">
|
||||
{{ $t('add_language') }}
|
||||
</MobileActionButton>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Languages -->
|
||||
<div @click="getLanguage(language)" v-for="language in languages" :key="language.data.id" class="flex items-center justify-between cursor-pointer py-2 pr-4 group">
|
||||
<label class="font-bold text-base" :class="{'text-theme': selectedLanguage && selectedLanguage.data.attributes.locale === language.data.attributes.locale}">
|
||||
{{ language.data.attributes.name }}
|
||||
</label>
|
||||
<x-icon
|
||||
v-if="language.data.attributes.locale !== 'en'"
|
||||
@click.stop="deleteLanguage(language)"
|
||||
class="group-hover:opacity-100 opacity-0"
|
||||
size="12"
|
||||
/>
|
||||
</div>
|
||||
<!--Content-->
|
||||
<div class="dynamic-content">
|
||||
<Spinner v-if="!selectedLanguage" class="spinner" />
|
||||
|
||||
<!-- Create Language button -->
|
||||
<MobileActionButton @click.native="createLanguage" icon="plus" class="mt-5 whitespace-nowrap">
|
||||
{{ $t('add_language') }}
|
||||
</MobileActionButton>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="selectedLanguage">
|
||||
<!--Language Settings-->
|
||||
<div v-if="!isSearching" class="card shadow-card">
|
||||
<FormLabel icon="settings">
|
||||
{{ $t('language_settings') }}
|
||||
</FormLabel>
|
||||
|
||||
<!--Content-->
|
||||
<div class="dynamic-content">
|
||||
<ValidationProvider tag="div" mode="passive" name="Language name" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('language_name')" :error="errors[0]">
|
||||
<input
|
||||
@input="$updateText(`/admin/languages/${selectedLanguage.data.id}`, 'name', selectedLanguage.data.attributes.name)"
|
||||
v-model="selectedLanguage.data.attributes.name"
|
||||
:placeholder="$t('admin_settings.appearance.description_plac')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<Spinner v-if="! selectedLanguage" class="spinner" />
|
||||
<AppInputSwitch
|
||||
:title="$t('set_as_default_language')"
|
||||
:description="$t('If this language is set as default, app will appear in this language for all users.')"
|
||||
:is-last="true"
|
||||
>
|
||||
<SwitchInput
|
||||
@input="setDefaultLanguage"
|
||||
class="switch"
|
||||
:class="{
|
||||
'disable-switch': selectedLanguage.data.attributes.locale === this.defaultLanguageLocale,
|
||||
}"
|
||||
:state="selectedLanguage.data.attributes.locale === this.defaultLanguageLocale"
|
||||
/>
|
||||
</AppInputSwitch>
|
||||
</div>
|
||||
|
||||
<div v-if="selectedLanguage">
|
||||
<div v-if="selectedLanguage" class="card shadow-card">
|
||||
<!--Translations-->
|
||||
<FormLabel>
|
||||
{{ $t('edit_translations') }}
|
||||
</FormLabel>
|
||||
|
||||
<!--Language Settings-->
|
||||
<div v-if="! isSearching" class="card shadow-card">
|
||||
<FormLabel icon="settings">
|
||||
{{ $t('language_settings') }}
|
||||
</FormLabel>
|
||||
<InfoBox>
|
||||
<p>
|
||||
Please preserve in your translations special string variables defined in format as
|
||||
<b class="text-theme">:variable</b> or <b class="text-theme">{variable}</b>.
|
||||
</p>
|
||||
</InfoBox>
|
||||
|
||||
<ValidationProvider tag="div" mode="passive" name="Language name" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('language_name')" :error="errors[0]">
|
||||
<input @input="$updateText(`/admin/languages/${selectedLanguage.data.id}`, 'name', selectedLanguage.data.attributes.name)" v-model="selectedLanguage.data.attributes.name" :placeholder="$t('admin_settings.appearance.description_plac')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<!--Inline Search for mobile-->
|
||||
<div class="sticky top-0 z-10 mb-8 hidden md:block">
|
||||
<SearchInput v-model="query" @reset-query="query = ''" />
|
||||
</div>
|
||||
|
||||
<AppInputSwitch :title="$t('set_as_default_language')" :description="$t('If this language is set as default, app will appear in this language for all users.')" :is-last="true">
|
||||
<SwitchInput
|
||||
@input="setDefaultLanguage"
|
||||
class="switch"
|
||||
:class="{'disable-switch': selectedLanguage.data.attributes.locale === this.defaultLanguageLocale }"
|
||||
:state="selectedLanguage.data.attributes.locale === this.defaultLanguageLocale"
|
||||
/>
|
||||
</AppInputSwitch>
|
||||
</div>
|
||||
<ValidationProvider tag="div" name="Language string" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="referenceTranslations[key]" :error="errors[0]" v-for="(translation, key) in translationList" :key="key">
|
||||
<textarea
|
||||
v-model="selectedLanguage.data.attributes.translations[key]"
|
||||
@input="$updateText(`/admin/languages/${selectedLanguage.data.id}/strings`, key, selectedLanguage.data.attributes.translations[key])"
|
||||
:rows="selectedLanguage.data.attributes.translations[key].length >= 80 ? 3 : 1"
|
||||
class="focus-border-theme input-dark"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
></textarea>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="selectedLanguage" class="card shadow-card">
|
||||
<!--Translations-->
|
||||
<FormLabel>
|
||||
{{ $t('edit_translations') }}
|
||||
</FormLabel>
|
||||
|
||||
<InfoBox>
|
||||
<p>Please preserve in your translations special string variables defined in format as <b class="text-theme">:variable</b> or <b class="text-theme">{variable}</b>.</p>
|
||||
</InfoBox>
|
||||
|
||||
<!--Inline Search for mobile-->
|
||||
<div class="sticky top-0 z-10 mb-8 md:block hidden">
|
||||
<SearchInput v-model="query" @reset-query="query = ''" />
|
||||
</div>
|
||||
|
||||
<ValidationProvider tag="div" name="Language string" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="referenceTranslations[key]" :error="errors[0]" v-for="(translation, key) in translationList" :key="key">
|
||||
<textarea
|
||||
v-model="selectedLanguage.data.attributes.translations[key]"
|
||||
@input="$updateText(`/admin/languages/${selectedLanguage.data.id}/strings`, key, selectedLanguage.data.attributes.translations[key])"
|
||||
:rows="selectedLanguage.data.attributes.translations[key].length >= 80 ? 3 : 1"
|
||||
class="focus-border-theme input-dark"
|
||||
:class="{'border-red': errors[0]}"
|
||||
></textarea>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Spinner v-if="! languages" />
|
||||
</div>
|
||||
<Spinner v-if="!languages" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AppInputSwitch from "../../../components/Admin/AppInputSwitch";
|
||||
import AppInputText from "../../../components/Admin/AppInputText";
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import MobileActionButton from "../../../components/FilesView/MobileActionButton";
|
||||
import SwitchInput from "../../../components/Others/Forms/SwitchInput";
|
||||
import SearchInput from "../../../components/Others/Forms/SearchInput";
|
||||
import FormLabel from "../../../components/Others/Forms/FormLabel";
|
||||
import MobileHeader from "../../../components/Mobile/MobileHeader";
|
||||
import ButtonBase from "../../../components/FilesView/ButtonBase";
|
||||
import InfoBox from "../../../components/Others/Forms/InfoBox";
|
||||
import PageHeader from "../../../components/Others/PageHeader";
|
||||
import Spinner from "../../../components/FilesView/Spinner";
|
||||
import {PlusIcon, XIcon} from 'vue-feather-icons'
|
||||
import {debounce, omitBy} from 'lodash'
|
||||
import {events} from '../../../bus'
|
||||
import AppInputSwitch from '../../../components/Admin/AppInputSwitch'
|
||||
import AppInputText from '../../../components/Admin/AppInputText'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import MobileActionButton from '../../../components/FilesView/MobileActionButton'
|
||||
import SwitchInput from '../../../components/Others/Forms/SwitchInput'
|
||||
import SearchInput from '../../../components/Others/Forms/SearchInput'
|
||||
import FormLabel from '../../../components/Others/Forms/FormLabel'
|
||||
import MobileHeader from '../../../components/Mobile/MobileHeader'
|
||||
import ButtonBase from '../../../components/FilesView/ButtonBase'
|
||||
import InfoBox from '../../../components/Others/Forms/InfoBox'
|
||||
import PageHeader from '../../../components/Others/PageHeader'
|
||||
import Spinner from '../../../components/FilesView/Spinner'
|
||||
import { PlusIcon, XIcon } from 'vue-feather-icons'
|
||||
import { debounce, omitBy } from 'lodash'
|
||||
import { events } from '../../../bus'
|
||||
|
||||
export default {
|
||||
name: 'Language',
|
||||
components: {
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
MobileActionButton,
|
||||
AppInputSwitch,
|
||||
AppInputText,
|
||||
MobileHeader,
|
||||
SearchInput,
|
||||
SwitchInput,
|
||||
ButtonBase,
|
||||
PageHeader,
|
||||
FormLabel,
|
||||
PlusIcon,
|
||||
InfoBox,
|
||||
Spinner,
|
||||
XIcon
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
searchedTranslationResults: undefined,
|
||||
referenceTranslations: undefined,
|
||||
export default {
|
||||
name: 'Language',
|
||||
components: {
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
MobileActionButton,
|
||||
AppInputSwitch,
|
||||
AppInputText,
|
||||
MobileHeader,
|
||||
SearchInput,
|
||||
SwitchInput,
|
||||
ButtonBase,
|
||||
PageHeader,
|
||||
FormLabel,
|
||||
PlusIcon,
|
||||
InfoBox,
|
||||
Spinner,
|
||||
XIcon,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
searchedTranslationResults: undefined,
|
||||
referenceTranslations: undefined,
|
||||
|
||||
defaultLanguageLocale: undefined,
|
||||
selectedLanguage: undefined,
|
||||
languages: undefined,
|
||||
query: '',
|
||||
defaultLanguageLocale: undefined,
|
||||
selectedLanguage: undefined,
|
||||
languages: undefined,
|
||||
query: '',
|
||||
|
||||
fixedNav: false,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
query: debounce(function (val) {
|
||||
this.searchedTranslationResults = omitBy(this.selectedLanguage.data.attributes.translations, string => {
|
||||
return !string.toLowerCase().includes(val.toLowerCase())
|
||||
})
|
||||
|
||||
var container = document.getElementById('single-page')
|
||||
|
||||
container.scrollTop = 0
|
||||
}, 300),
|
||||
},
|
||||
computed: {
|
||||
isSearching() {
|
||||
return this.searchedTranslationResults && this.query !== ''
|
||||
},
|
||||
translationList() {
|
||||
return this.isSearching
|
||||
? this.searchedTranslationResults
|
||||
: this.selectedLanguage.data.attributes.translations
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setDefaultLanguage() {
|
||||
this.$updateText('/admin/settings', 'language', this.selectedLanguage.data.attributes.locale)
|
||||
this.defaultLanguageLocale = this.selectedLanguage.data.attributes.locale
|
||||
|
||||
setTimeout(() => location.reload(), 500)
|
||||
},
|
||||
getLanguages() {
|
||||
axios
|
||||
.get('/api/admin/languages')
|
||||
.then(response => {
|
||||
this.languages = response.data.data
|
||||
this.referenceTranslations = response.data.meta.reference_translations
|
||||
this.selectedLanguage = response.data.meta.current_language
|
||||
this.defaultLanguageLocale = response.data.meta.current_language.data.attributes.locale
|
||||
})
|
||||
.catch(() => {
|
||||
this.$isSomethingWrong()
|
||||
})
|
||||
},
|
||||
getLanguage(language) {
|
||||
this.selectedLanguage = undefined
|
||||
|
||||
axios
|
||||
.get(`/api/admin/languages/${language.data.id}`)
|
||||
.then(response => {
|
||||
this.selectedLanguage = response.data
|
||||
})
|
||||
.catch(() => {
|
||||
this.$isSomethingWrong()
|
||||
})
|
||||
},
|
||||
deleteLanguage(language) {
|
||||
events.$emit('confirm:open', {
|
||||
title: `Delete "${language.data.attributes.name}" language?`,
|
||||
message: 'Your language will be permanently deleted.',
|
||||
buttonColor: 'danger-solid',
|
||||
action: {
|
||||
id: language.data.id,
|
||||
operation: 'delete-language'
|
||||
}
|
||||
})
|
||||
},
|
||||
createLanguage() {
|
||||
events.$emit('popup:open', {name: 'create-language'})
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getLanguages()
|
||||
|
||||
events.$on('reload:languages', () => this.getLanguages())
|
||||
|
||||
events.$on('action:confirmed', data => {
|
||||
|
||||
if (data.operation === 'delete-language')
|
||||
axios.delete(`/api/admin/languages/${data.id}`)
|
||||
.then(() => this.getLanguages())
|
||||
.catch(() => this.$isSomethingWrong())
|
||||
fixedNav: false,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
query: debounce(function (val) {
|
||||
this.searchedTranslationResults = omitBy(this.selectedLanguage.data.attributes.translations, (string) => {
|
||||
return !string.toLowerCase().includes(val.toLowerCase())
|
||||
})
|
||||
|
||||
// Handle fixed mobile navigation
|
||||
window.addEventListener("scroll", () => {
|
||||
let card = document.getElementById('card-navigation')
|
||||
var container = document.getElementById('single-page')
|
||||
|
||||
this.fixedNav = card.getBoundingClientRect().top < 0;
|
||||
});
|
||||
container.scrollTop = 0
|
||||
}, 300),
|
||||
},
|
||||
computed: {
|
||||
isSearching() {
|
||||
return this.searchedTranslationResults && this.query !== ''
|
||||
},
|
||||
destroyed() {
|
||||
events.$off('action:confirmed')
|
||||
translationList() {
|
||||
return this.isSearching ? this.searchedTranslationResults : this.selectedLanguage.data.attributes.translations
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
setDefaultLanguage() {
|
||||
this.$updateText('/admin/settings', 'language', this.selectedLanguage.data.attributes.locale)
|
||||
this.defaultLanguageLocale = this.selectedLanguage.data.attributes.locale
|
||||
|
||||
setTimeout(() => location.reload(), 500)
|
||||
},
|
||||
getLanguages() {
|
||||
axios
|
||||
.get('/api/admin/languages')
|
||||
.then((response) => {
|
||||
this.languages = response.data.data
|
||||
this.referenceTranslations = response.data.meta.reference_translations
|
||||
this.selectedLanguage = response.data.meta.current_language
|
||||
this.defaultLanguageLocale = response.data.meta.current_language.data.attributes.locale
|
||||
})
|
||||
.catch(() => {
|
||||
this.$isSomethingWrong()
|
||||
})
|
||||
},
|
||||
getLanguage(language) {
|
||||
this.selectedLanguage = undefined
|
||||
|
||||
axios
|
||||
.get(`/api/admin/languages/${language.data.id}`)
|
||||
.then((response) => {
|
||||
this.selectedLanguage = response.data
|
||||
})
|
||||
.catch(() => {
|
||||
this.$isSomethingWrong()
|
||||
})
|
||||
},
|
||||
deleteLanguage(language) {
|
||||
events.$emit('confirm:open', {
|
||||
title: `Delete "${language.data.attributes.name}" language?`,
|
||||
message: 'Your language will be permanently deleted.',
|
||||
buttonColor: 'danger-solid',
|
||||
action: {
|
||||
id: language.data.id,
|
||||
operation: 'delete-language',
|
||||
},
|
||||
})
|
||||
},
|
||||
createLanguage() {
|
||||
events.$emit('popup:open', { name: 'create-language' })
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.getLanguages()
|
||||
|
||||
events.$on('reload:languages', () => this.getLanguages())
|
||||
|
||||
events.$on('action:confirmed', (data) => {
|
||||
if (data.operation === 'delete-language')
|
||||
axios
|
||||
.delete(`/api/admin/languages/${data.id}`)
|
||||
.then(() => this.getLanguages())
|
||||
.catch(() => this.$isSomethingWrong())
|
||||
})
|
||||
|
||||
// Handle fixed mobile navigation
|
||||
window.addEventListener('scroll', () => {
|
||||
let card = document.getElementById('card-navigation')
|
||||
|
||||
this.fixedNav = card.getBoundingClientRect().top < 0
|
||||
})
|
||||
},
|
||||
destroyed() {
|
||||
events.$off('action:confirmed')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,93 +1,113 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="card shadow-card">
|
||||
<DatatableWrapper @init="isLoading = false" api="/api/admin/pages" :paginator="false" :columns="columns" class="overflow-x-auto">
|
||||
<template slot-scope="{ row }">
|
||||
<tr class="border-b dark:border-opacity-5 border-light border-dashed whitespace-nowrap">
|
||||
<td class="py-5 md:pr-1 pr-3">
|
||||
<router-link :to="{name: 'PageEdit', params: {slug: row.data.attributes.slug}}" class="text-sm font-bold cursor-pointer" tag="div">
|
||||
{{ row.data.attributes.title }}
|
||||
</router-link>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<span class="text-sm font-bold">
|
||||
{{ row.data.attributes.slug }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<span class="text-sm font-bold">
|
||||
<SwitchInput @input="$updateText(`/admin/pages/${row.data.id}`, 'visibility', row.data.attributes.visibility)" v-model="row.data.attributes.visibility" :state="row.data.attributes.visibility" class="switch"/>
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:pl-1 pl-3 text-right">
|
||||
<div class="flex space-x-2 w-full justify-end">
|
||||
<router-link class="flex items-center justify-center w-8 h-8 rounded-md dark:bg-2x-dark-foreground hover:bg-green-100 bg-light-background transition-colors" :to="{name: 'PageEdit', params: {slug: row.data.attributes.slug}}">
|
||||
<Edit2Icon size="15" class="opacity-75" />
|
||||
</router-link>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</DatatableWrapper>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="card shadow-card">
|
||||
<DatatableWrapper @init="isLoading = false" api="/api/admin/pages" :paginator="false" :columns="columns" class="overflow-x-auto">
|
||||
<template slot-scope="{ row }">
|
||||
<tr class="whitespace-nowrap border-b border-dashed border-light dark:border-opacity-5">
|
||||
<td class="py-5 pr-3 md:pr-1">
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'PageEdit',
|
||||
params: { slug: row.data.attributes.slug },
|
||||
}"
|
||||
class="cursor-pointer text-sm font-bold"
|
||||
tag="div"
|
||||
>
|
||||
{{ row.data.attributes.title }}
|
||||
</router-link>
|
||||
</td>
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="text-sm font-bold">
|
||||
{{ row.data.attributes.slug }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="text-sm font-bold">
|
||||
<SwitchInput
|
||||
@input="$updateText(`/admin/pages/${row.data.id}`, 'visibility', row.data.attributes.visibility)"
|
||||
v-model="row.data.attributes.visibility"
|
||||
:state="row.data.attributes.visibility"
|
||||
class="switch"
|
||||
/>
|
||||
</span>
|
||||
</td>
|
||||
<td class="pl-3 text-right md:pl-1">
|
||||
<div class="flex w-full justify-end space-x-2">
|
||||
<router-link
|
||||
class="flex h-8 w-8 items-center justify-center rounded-md bg-light-background transition-colors hover:bg-green-100 dark:bg-2x-dark-foreground"
|
||||
:to="{
|
||||
name: 'PageEdit',
|
||||
params: {
|
||||
slug: row.data.attributes.slug,
|
||||
},
|
||||
}"
|
||||
>
|
||||
<Edit2Icon size="15" class="opacity-75" />
|
||||
</router-link>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</DatatableWrapper>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DatatableWrapper from "../../components/Others/Tables/DatatableWrapper";
|
||||
import MobileActionButton from "../../components/FilesView/MobileActionButton";
|
||||
import EmptyPageContent from "../../components/Others/EmptyPageContent";
|
||||
import SwitchInput from "../../components/Others/Forms/SwitchInput";
|
||||
import MobileHeader from "../../components/Mobile/MobileHeader";
|
||||
import SectionTitle from "../../components/Others/SectionTitle";
|
||||
import ButtonBase from "../../components/FilesView/ButtonBase";
|
||||
import {Trash2Icon, Edit2Icon} from "vue-feather-icons";
|
||||
import PageHeader from "../../components/Others/PageHeader";
|
||||
import ColorLabel from "../../components/Others/ColorLabel";
|
||||
import Spinner from "../../components/FilesView/Spinner";
|
||||
import axios from 'axios'
|
||||
import DatatableWrapper from '../../components/Others/Tables/DatatableWrapper'
|
||||
import MobileActionButton from '../../components/FilesView/MobileActionButton'
|
||||
import EmptyPageContent from '../../components/Others/EmptyPageContent'
|
||||
import SwitchInput from '../../components/Others/Forms/SwitchInput'
|
||||
import MobileHeader from '../../components/Mobile/MobileHeader'
|
||||
import SectionTitle from '../../components/Others/SectionTitle'
|
||||
import ButtonBase from '../../components/FilesView/ButtonBase'
|
||||
import { Trash2Icon, Edit2Icon } from 'vue-feather-icons'
|
||||
import PageHeader from '../../components/Others/PageHeader'
|
||||
import ColorLabel from '../../components/Others/ColorLabel'
|
||||
import Spinner from '../../components/FilesView/Spinner'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'Pages',
|
||||
components: {
|
||||
MobileActionButton,
|
||||
EmptyPageContent,
|
||||
DatatableWrapper,
|
||||
SectionTitle,
|
||||
MobileHeader,
|
||||
SwitchInput,
|
||||
Trash2Icon,
|
||||
PageHeader,
|
||||
ButtonBase,
|
||||
ColorLabel,
|
||||
Edit2Icon,
|
||||
Spinner,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
columns: [
|
||||
{
|
||||
label: this.$t('admin_pages.table.page'),
|
||||
field: 'title',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_pages.table.slug'),
|
||||
field: 'slug',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_pages.table.status'),
|
||||
field: 'visibility',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
sortable: false
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
export default {
|
||||
name: 'Pages',
|
||||
components: {
|
||||
MobileActionButton,
|
||||
EmptyPageContent,
|
||||
DatatableWrapper,
|
||||
SectionTitle,
|
||||
MobileHeader,
|
||||
SwitchInput,
|
||||
Trash2Icon,
|
||||
PageHeader,
|
||||
ButtonBase,
|
||||
ColorLabel,
|
||||
Edit2Icon,
|
||||
Spinner,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
columns: [
|
||||
{
|
||||
label: this.$t('admin_pages.table.page'),
|
||||
field: 'title',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_pages.table.slug'),
|
||||
field: 'slug',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_pages.table.status'),
|
||||
field: 'visibility',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
sortable: false,
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,29 +1,34 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="! isLoading && page" class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ page.data.attributes.title }}
|
||||
</FormLabel>
|
||||
<AppInputSwitch :title="$t('admin_pages.form.visibility')" :description="$t('admin_pages.form.visibility_help')">
|
||||
<SwitchInput @input="changeStatus" class="switch" :state="page.data.attributes.visibility"/>
|
||||
</AppInputSwitch>
|
||||
<AppInputText :title="$t('admin_pages.form.title')">
|
||||
<input @input="$updateText('/admin/pages/' + $route.params.slug, 'title', page.data.attributes.title)" v-model="page.data.attributes.title"
|
||||
:placeholder="$t('admin_pages.form.title_plac')" type="text" class="focus-border-theme input-dark"/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('admin_pages.form.slug')">
|
||||
<input v-model="page.data.attributes.slug" type="text" class="focus-border-theme input-dark" disabled/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('admin_pages.form.content')" :is-last="true">
|
||||
<textarea
|
||||
@input="$updateText('/admin/pages/' + $route.params.slug, 'content', page.data.attributes.content)"
|
||||
v-model="page.data.attributes.content"
|
||||
:placeholder="$t('admin_pages.form.content_plac')"
|
||||
class="focus-border-theme input-dark"
|
||||
rows="18"
|
||||
></textarea>
|
||||
</AppInputText>
|
||||
</div>
|
||||
<div v-if="!isLoading && page" class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ page.data.attributes.title }}
|
||||
</FormLabel>
|
||||
<AppInputSwitch :title="$t('admin_pages.form.visibility')" :description="$t('admin_pages.form.visibility_help')">
|
||||
<SwitchInput @input="changeStatus" class="switch" :state="page.data.attributes.visibility" />
|
||||
</AppInputSwitch>
|
||||
<AppInputText :title="$t('admin_pages.form.title')">
|
||||
<input
|
||||
@input="$updateText('/admin/pages/' + $route.params.slug, 'title', page.data.attributes.title)"
|
||||
v-model="page.data.attributes.title"
|
||||
:placeholder="$t('admin_pages.form.title_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('admin_pages.form.slug')">
|
||||
<input v-model="page.data.attributes.slug" type="text" class="focus-border-theme input-dark" disabled />
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('admin_pages.form.content')" :is-last="true">
|
||||
<textarea
|
||||
@input="$updateText('/admin/pages/' + $route.params.slug, 'content', page.data.attributes.content)"
|
||||
v-model="page.data.attributes.content"
|
||||
:placeholder="$t('admin_pages.form.content_plac')"
|
||||
class="focus-border-theme input-dark"
|
||||
rows="18"
|
||||
></textarea>
|
||||
</AppInputText>
|
||||
</div>
|
||||
<div id="loader" v-if="isLoading">
|
||||
<Spinner></Spinner>
|
||||
</div>
|
||||
@@ -31,52 +36,51 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AppInputSwitch from "../../../components/Admin/AppInputSwitch";
|
||||
import AppInputText from "../../../components/Admin/AppInputText";
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import FormLabel from "../../../components/Others/Forms/FormLabel";
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import SwitchInput from "../../../components/Others/Forms/SwitchInput";
|
||||
import MobileHeader from "../../../components/Mobile/MobileHeader";
|
||||
import SectionTitle from "../../../components/Others/SectionTitle";
|
||||
import ButtonBase from "../../../components/FilesView/ButtonBase";
|
||||
import PageHeader from "../../../components/Others/PageHeader";
|
||||
import Spinner from "../../../components/FilesView/Spinner";
|
||||
import axios from 'axios'
|
||||
import AppInputSwitch from '../../../components/Admin/AppInputSwitch'
|
||||
import AppInputText from '../../../components/Admin/AppInputText'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import FormLabel from '../../../components/Others/Forms/FormLabel'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import SwitchInput from '../../../components/Others/Forms/SwitchInput'
|
||||
import MobileHeader from '../../../components/Mobile/MobileHeader'
|
||||
import SectionTitle from '../../../components/Others/SectionTitle'
|
||||
import ButtonBase from '../../../components/FilesView/ButtonBase'
|
||||
import PageHeader from '../../../components/Others/PageHeader'
|
||||
import Spinner from '../../../components/FilesView/Spinner'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'PageEdit',
|
||||
components: {
|
||||
AppInputSwitch,
|
||||
AppInputText,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
FormLabel,
|
||||
SectionTitle,
|
||||
MobileHeader,
|
||||
SwitchInput,
|
||||
PageHeader,
|
||||
ButtonBase,
|
||||
required,
|
||||
Spinner,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
page: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeStatus(val) {
|
||||
this.$updateText('/admin/pages/' + this.$route.params.slug , 'visibility', val)
|
||||
}
|
||||
},
|
||||
created() {
|
||||
axios.get('/api/admin/pages/' + this.$route.params.slug)
|
||||
.then(response => {
|
||||
this.page = response.data
|
||||
this.isLoading = false
|
||||
})
|
||||
export default {
|
||||
name: 'PageEdit',
|
||||
components: {
|
||||
AppInputSwitch,
|
||||
AppInputText,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
FormLabel,
|
||||
SectionTitle,
|
||||
MobileHeader,
|
||||
SwitchInput,
|
||||
PageHeader,
|
||||
ButtonBase,
|
||||
required,
|
||||
Spinner,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
page: undefined,
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
changeStatus(val) {
|
||||
this.$updateText('/admin/pages/' + this.$route.params.slug, 'visibility', val)
|
||||
},
|
||||
},
|
||||
created() {
|
||||
axios.get('/api/admin/pages/' + this.$route.params.slug).then((response) => {
|
||||
this.page = response.data
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,39 +1,39 @@
|
||||
<template>
|
||||
<div>
|
||||
<!--Page Tab links-->
|
||||
<div class="card shadow-card z-10" style="padding-bottom: 0; padding-top: 0;">
|
||||
<CardNavigation :pages="pages" class="-mx-1" />
|
||||
</div>
|
||||
<!--Page Tab links-->
|
||||
<div class="card z-10 shadow-card" style="padding-bottom: 0; padding-top: 0">
|
||||
<CardNavigation :pages="pages" class="-mx-1" />
|
||||
</div>
|
||||
|
||||
<!--Page Content-->
|
||||
<router-view />
|
||||
<!--Page Content-->
|
||||
<router-view />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CardNavigation from "../../../components/Admin/CardNavigation";
|
||||
import CardNavigation from '../../../components/Admin/CardNavigation'
|
||||
|
||||
export default {
|
||||
name: 'PaymentSettings',
|
||||
components: {
|
||||
CardNavigation,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
title: this.$t('admin_settings.tabs.payments'),
|
||||
route: 'AppPayments',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_settings.tabs.billings'),
|
||||
route: 'AppBillings',
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$router.replace({name: 'AppPayments'})
|
||||
}
|
||||
}
|
||||
export default {
|
||||
name: 'PaymentSettings',
|
||||
components: {
|
||||
CardNavigation,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
title: this.$t('admin_settings.tabs.payments'),
|
||||
route: 'AppPayments',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_settings.tabs.billings'),
|
||||
route: 'AppBillings',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$router.replace({ name: 'AppPayments' })
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,114 +1,161 @@
|
||||
<template>
|
||||
<PageTab :is-loading="isLoading">
|
||||
<div v-if="billingInformation" class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('admin_settings.billings.section_company') }}
|
||||
</FormLabel>
|
||||
<div v-if="billingInformation" class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('admin_settings.billings.section_company') }}
|
||||
</FormLabel>
|
||||
|
||||
<AppInputText :title="$t('admin_settings.billings.company_name')">
|
||||
<input @input="$updateText('/admin/settings', 'billing_name', billingInformation.billing_name)" v-model="billingInformation.billing_name" :placeholder="$t('admin_settings.billings.company_name_plac')" type="text" class="focus-border-theme input-dark"/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('admin_settings.billings.company_name')">
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'billing_name', billingInformation.billing_name)"
|
||||
v-model="billingInformation.billing_name"
|
||||
:placeholder="$t('admin_settings.billings.company_name_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
|
||||
<AppInputText :title="$t('admin_settings.billings.vat')" :is-last="true">
|
||||
<input @input="$updateText('/admin/settings', 'billing_vat_number', billingInformation.billing_vat_number)" v-model="billingInformation.billing_vat_number" :placeholder="$t('admin_settings.billings.vat_plac')" type="text" class="focus-border-theme input-dark"/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
<div v-if="billingInformation" class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('admin_settings.billings.section_billing') }}
|
||||
</FormLabel>
|
||||
<AppInputText :title="$t('admin_settings.billings.vat')" :is-last="true">
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'billing_vat_number', billingInformation.billing_vat_number)"
|
||||
v-model="billingInformation.billing_vat_number"
|
||||
:placeholder="$t('admin_settings.billings.vat_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
<div v-if="billingInformation" class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('admin_settings.billings.section_billing') }}
|
||||
</FormLabel>
|
||||
|
||||
<AppInputText :title="$t('admin_settings.billings.country')">
|
||||
<SelectInput @input="$updateText('/admin/settings', 'billing_country', billingInformation.billing_country)" v-model="billingInformation.billing_country" :default="billingInformation.billing_country" :options="countries" :placeholder="$t('admin_settings.billings.country_plac')"/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('admin_settings.billings.country')">
|
||||
<SelectInput
|
||||
@input="$updateText('/admin/settings', 'billing_country', billingInformation.billing_country)"
|
||||
v-model="billingInformation.billing_country"
|
||||
:default="billingInformation.billing_country"
|
||||
:options="countries"
|
||||
:placeholder="$t('admin_settings.billings.country_plac')"
|
||||
/>
|
||||
</AppInputText>
|
||||
|
||||
<AppInputText :title="$t('admin_settings.billings.address')">
|
||||
<input @input="$updateText('/admin/settings', 'billing_address', billingInformation.billing_address)" v-model="billingInformation.billing_address" :placeholder="$t('admin_settings.billings.address_plac')" type="text" class="focus-border-theme input-dark"/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('admin_settings.billings.address')">
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'billing_address', billingInformation.billing_address)"
|
||||
v-model="billingInformation.billing_address"
|
||||
:placeholder="$t('admin_settings.billings.address_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
|
||||
<div class="flex space-x-4">
|
||||
<AppInputText :title="$t('admin_settings.billings.city')" class="w-full">
|
||||
<input @input="$updateText('/admin/settings', 'billing_city', billingInformation.billing_city)" v-model="billingInformation.billing_city" :placeholder="$t('admin_settings.billings.city_plac')" type="text" class="focus-border-theme input-dark"/>
|
||||
</AppInputText>
|
||||
<div class="flex space-x-4">
|
||||
<AppInputText :title="$t('admin_settings.billings.city')" class="w-full">
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'billing_city', billingInformation.billing_city)"
|
||||
v-model="billingInformation.billing_city"
|
||||
:placeholder="$t('admin_settings.billings.city_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
|
||||
<AppInputText :title="$t('admin_settings.billings.postal_code')" class="w-full">
|
||||
<input @input="$updateText('/admin/settings', 'billing_postal_code', billingInformation.billing_postal_code)" v-model="billingInformation.billing_postal_code" :placeholder="$t('admin_settings.billings.postal_code_plac')" type="text" class="focus-border-theme input-dark"/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
<AppInputText :title="$t('admin_settings.billings.postal_code')" class="w-full">
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'billing_postal_code', billingInformation.billing_postal_code)"
|
||||
v-model="billingInformation.billing_postal_code"
|
||||
:placeholder="$t('admin_settings.billings.postal_code_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
|
||||
<AppInputText :title="$t('admin_settings.billings.state')">
|
||||
<input @input="$updateText('/admin/settings', 'billing_state', billingInformation.billing_state)" v-model="billingInformation.billing_state" :placeholder="$t('admin_settings.billings.state_plac')" type="text" class="focus-border-theme input-dark"/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('admin_settings.billings.state')">
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'billing_state', billingInformation.billing_state)"
|
||||
v-model="billingInformation.billing_state"
|
||||
:placeholder="$t('admin_settings.billings.state_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
|
||||
<AppInputText :title="$t('admin_settings.billings.phone_number')" :is-last="true">
|
||||
<input @input="$updateText('/admin/settings', 'billing_phone_number', billingInformation.billing_phone_number)" v-model="billingInformation.billing_phone_number" :placeholder="$t('admin_settings.billings.phone_number_plac')" type="text" class="focus-border-theme input-dark"/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
<AppInputText :title="$t('admin_settings.billings.phone_number')" :is-last="true">
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'billing_phone_number', billingInformation.billing_phone_number)"
|
||||
v-model="billingInformation.billing_phone_number"
|
||||
:placeholder="$t('admin_settings.billings.phone_number_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
</PageTab>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AppInputText from "../../../../components/Admin/AppInputText";
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import PageTabGroup from "../../../../components/Others/Layout/PageTabGroup";
|
||||
import SelectInput from "../../../../components/Others/Forms/SelectInput";
|
||||
import ImageInput from "../../../../components/Others/Forms/ImageInput";
|
||||
import FormLabel from "../../../../components/Others/Forms/FormLabel";
|
||||
import ButtonBase from "../../../../components/FilesView/ButtonBase";
|
||||
import SetupBox from "../../../../components/Others/Forms/SetupBox";
|
||||
import PageTab from "../../../../components/Others/Layout/PageTab";
|
||||
import InfoBox from "../../../../components/Others/Forms/InfoBox";
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import axios from 'axios'
|
||||
import { mapGetters } from 'vuex'
|
||||
import AppInputText from '../../../../components/Admin/AppInputText'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import PageTabGroup from '../../../../components/Others/Layout/PageTabGroup'
|
||||
import SelectInput from '../../../../components/Others/Forms/SelectInput'
|
||||
import ImageInput from '../../../../components/Others/Forms/ImageInput'
|
||||
import FormLabel from '../../../../components/Others/Forms/FormLabel'
|
||||
import ButtonBase from '../../../../components/FilesView/ButtonBase'
|
||||
import SetupBox from '../../../../components/Others/Forms/SetupBox'
|
||||
import PageTab from '../../../../components/Others/Layout/PageTab'
|
||||
import InfoBox from '../../../../components/Others/Forms/InfoBox'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import axios from 'axios'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'AppAppearance',
|
||||
components: {
|
||||
ValidationObserver,
|
||||
ValidationProvider,
|
||||
AppInputText,
|
||||
PageTabGroup,
|
||||
SelectInput,
|
||||
ImageInput,
|
||||
ButtonBase,
|
||||
FormLabel,
|
||||
SetupBox,
|
||||
required,
|
||||
PageTab,
|
||||
InfoBox,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'countries'
|
||||
]),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
billingInformation: undefined
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
axios.get('/api/admin/settings', {
|
||||
export default {
|
||||
name: 'AppAppearance',
|
||||
components: {
|
||||
ValidationObserver,
|
||||
ValidationProvider,
|
||||
AppInputText,
|
||||
PageTabGroup,
|
||||
SelectInput,
|
||||
ImageInput,
|
||||
ButtonBase,
|
||||
FormLabel,
|
||||
SetupBox,
|
||||
required,
|
||||
PageTab,
|
||||
InfoBox,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['countries']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
billingInformation: undefined,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
axios
|
||||
.get('/api/admin/settings', {
|
||||
params: {
|
||||
column: 'billing_phone_number|billing_postal_code|billing_vat_number|billing_address|billing_country|billing_state|billing_city|billing_name'
|
||||
column: 'billing_phone_number|billing_postal_code|billing_vat_number|billing_address|billing_country|billing_state|billing_city|billing_name',
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
this.isLoading = false
|
||||
|
||||
this.billingInformation = {
|
||||
billing_phone_number: response.data.billing_phone_number,
|
||||
billing_postal_code: response.data.billing_postal_code,
|
||||
billing_vat_number: response.data.billing_vat_number,
|
||||
billing_address: response.data.billing_address,
|
||||
billing_country: response.data.billing_country,
|
||||
billing_state: response.data.billing_state,
|
||||
billing_city: response.data.billing_city,
|
||||
billing_name: response.data.billing_name,
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
this.isLoading = false
|
||||
|
||||
this.billingInformation = {
|
||||
billing_phone_number: response.data.billing_phone_number,
|
||||
billing_postal_code: response.data.billing_postal_code,
|
||||
billing_vat_number: response.data.billing_vat_number,
|
||||
billing_address: response.data.billing_address,
|
||||
billing_country: response.data.billing_country,
|
||||
billing_state: response.data.billing_state,
|
||||
billing_city: response.data.billing_city,
|
||||
billing_name: response.data.billing_name,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,453 +1,562 @@
|
||||
<template>
|
||||
<PageTab>
|
||||
<!--Global payment settings-->
|
||||
<div class="card shadow-card">
|
||||
<FormLabel icon="dollar">
|
||||
{{ $t('Subscription Payments') }}
|
||||
</FormLabel>
|
||||
<!--Global payment settings-->
|
||||
<div class="card shadow-card">
|
||||
<FormLabel icon="dollar">
|
||||
{{ $t('Subscription Payments') }}
|
||||
</FormLabel>
|
||||
|
||||
<AppInputSwitch :title="$t('Allow Subscription Payments')" :description="$t('User can subscribe to fixed or metered plan')" :is-last="! allowedPayments">
|
||||
<SwitchInput @input="$updateText('/admin/settings', 'allowed_payments', allowedPayments)" v-model="allowedPayments" :state="allowedPayments" />
|
||||
</AppInputSwitch>
|
||||
<AppInputSwitch :title="$t('Allow Subscription Payments')" :description="$t('User can subscribe to fixed or metered plan')" :is-last="!allowedPayments">
|
||||
<SwitchInput @input="$updateText('/admin/settings', 'allowed_payments', allowedPayments)" v-model="allowedPayments" :state="allowedPayments" />
|
||||
</AppInputSwitch>
|
||||
|
||||
<AppInputText v-if="allowedPayments" :title="$t('Subscription Type')" :is-last="true">
|
||||
<SelectInput @change="subscriptionTypeChange" :default="config.subscriptionType" :options="subscriptionTypes" :placeholder="$t('Select your subscription type')"/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
<AppInputText v-if="allowedPayments" :title="$t('Subscription Type')" :is-last="true">
|
||||
<SelectInput @change="subscriptionTypeChange" :default="config.subscriptionType" :options="subscriptionTypes" :placeholder="$t('Select your subscription type')" />
|
||||
</AppInputText>
|
||||
</div>
|
||||
|
||||
<!--Metered settings-->
|
||||
<div v-if="config.subscriptionType === 'metered' && allowedPayments" class="card shadow-card">
|
||||
<FormLabel icon="bar-chart">
|
||||
{{ $t('Metered Billing Settings') }}
|
||||
</FormLabel>
|
||||
<!--Metered settings-->
|
||||
<div v-if="config.subscriptionType === 'metered' && allowedPayments" class="card shadow-card">
|
||||
<FormLabel icon="bar-chart">
|
||||
{{ $t('Metered Billing Settings') }}
|
||||
</FormLabel>
|
||||
|
||||
<AppInputSwitch :title="$t('Allow Registration Bonus')" :description="$t('Credit user automatically bonus to his balance after registration.')">
|
||||
<SwitchInput @input="$updateText('/admin/settings', 'allowed_registration_bonus', allowedRegistrationBonus)" v-model="allowedRegistrationBonus" :state="allowedRegistrationBonus" />
|
||||
</AppInputSwitch>
|
||||
<AppInputSwitch :title="$t('Allow Registration Bonus')" :description="$t('Credit user automatically bonus to his balance after registration.')">
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'allowed_registration_bonus', allowedRegistrationBonus)"
|
||||
v-model="allowedRegistrationBonus"
|
||||
:state="allowedRegistrationBonus"
|
||||
/>
|
||||
</AppInputSwitch>
|
||||
|
||||
<AppInputText v-if="allowedRegistrationBonus" :title="$t('The Amount of Registration Bonus')" :description="$t('This bonus will be automatically added when user successfully register his account.')">
|
||||
<input @input="$updateText('/admin/settings', 'registration_bonus_amount', registrationBonusAmount)" v-model="registrationBonusAmount" :placeholder="$t('Type registration bonus amount...')" type="number" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
<AppInputText
|
||||
v-if="allowedRegistrationBonus"
|
||||
:title="$t('The Amount of Registration Bonus')"
|
||||
:description="$t('This bonus will be automatically added when user successfully register his account.')"
|
||||
>
|
||||
<input
|
||||
@input="$updateText('/admin/settings', 'registration_bonus_amount', registrationBonusAmount)"
|
||||
v-model="registrationBonusAmount"
|
||||
:placeholder="$t('Type registration bonus amount...')"
|
||||
type="number"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
|
||||
<AppInputButton :title="$t('Metered Plan')" :description="$t('Your price set up for billing multiple features by user usage.')" :is-last="true">
|
||||
<router-link v-if="config.isCreatedMeteredPlan" :to="{name: 'PlanMeteredSettings', params: {id: config.meteredPlanId}}">
|
||||
<ButtonBase v-if="config.isCreatedMeteredPlan" class="sm:w-auto w-full" button-style="theme">
|
||||
{{ $t('Plan Details') }}
|
||||
</ButtonBase>
|
||||
</router-link>
|
||||
<AppInputButton :title="$t('Metered Plan')" :description="$t('Your price set up for billing multiple features by user usage.')" :is-last="true">
|
||||
<router-link
|
||||
v-if="config.isCreatedMeteredPlan"
|
||||
:to="{
|
||||
name: 'PlanMeteredSettings',
|
||||
params: { id: config.meteredPlanId },
|
||||
}"
|
||||
>
|
||||
<ButtonBase v-if="config.isCreatedMeteredPlan" class="w-full sm:w-auto" button-style="theme">
|
||||
{{ $t('Plan Details') }}
|
||||
</ButtonBase>
|
||||
</router-link>
|
||||
|
||||
<router-link v-if="! config.isCreatedMeteredPlan" :to="{name: 'CreateMeteredPlan'}">
|
||||
<ButtonBase class="sm:w-auto w-full" button-style="theme-solid">
|
||||
{{ $t('Create Plan') }}
|
||||
</ButtonBase>
|
||||
</router-link>
|
||||
</AppInputButton>
|
||||
</div>
|
||||
<router-link v-if="!config.isCreatedMeteredPlan" :to="{ name: 'CreateMeteredPlan' }">
|
||||
<ButtonBase class="w-full sm:w-auto" button-style="theme-solid">
|
||||
{{ $t('Create Plan') }}
|
||||
</ButtonBase>
|
||||
</router-link>
|
||||
</AppInputButton>
|
||||
</div>
|
||||
|
||||
<!--Stripe method configuration-->
|
||||
<div v-if="allowedPayments" class="card shadow-card">
|
||||
<img :src="$getPaymentLogo('stripe')" alt="Stripe" class="mb-8 h-8">
|
||||
<!--Stripe method configuration-->
|
||||
<div v-if="allowedPayments" class="card shadow-card">
|
||||
<img :src="$getPaymentLogo('stripe')" alt="Stripe" class="mb-8 h-8" />
|
||||
|
||||
<AppInputSwitch :title="$t('Allow Stripe Service')" :description="$t('Allow your users pay by their credit card')" :is-last="! stripe.allowedService">
|
||||
<SwitchInput @input="$updateText('/admin/settings', 'allowed_stripe', stripe.allowedService)" v-model="stripe.allowedService" :state="stripe.allowedService" />
|
||||
</AppInputSwitch>
|
||||
<AppInputSwitch :title="$t('Allow Stripe Service')" :description="$t('Allow your users pay by their credit card')" :is-last="!stripe.allowedService">
|
||||
<SwitchInput @input="$updateText('/admin/settings', 'allowed_stripe', stripe.allowedService)" v-model="stripe.allowedService" :state="stripe.allowedService" />
|
||||
</AppInputSwitch>
|
||||
|
||||
<!--Stripe credentials are set up-->
|
||||
<div v-if="stripe.allowedService">
|
||||
<div v-if="stripe.isConfigured">
|
||||
<AppInputText @input="$updateText('/admin/settings', 'stripe_payment_description', stripe.paymentDescription)" :title="$t('Payment Description')" :description="$t('The description showed below user payment method selection.')">
|
||||
<textarea rows="2" @input="$updateText('/admin/settings', 'stripe_payment_description', stripe.paymentDescription, true)" v-model="stripe.paymentDescription" :placeholder="$t('Describe in short which methods user can pay with this payment method...')" type="text" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
<!--Stripe credentials are set up-->
|
||||
<div v-if="stripe.allowedService">
|
||||
<div v-if="stripe.isConfigured">
|
||||
<AppInputText
|
||||
@input="$updateText('/admin/settings', 'stripe_payment_description', stripe.paymentDescription)"
|
||||
:title="$t('Payment Description')"
|
||||
:description="$t('The description showed below user payment method selection.')"
|
||||
>
|
||||
<textarea
|
||||
rows="2"
|
||||
@input="$updateText('/admin/settings', 'stripe_payment_description', stripe.paymentDescription, true)"
|
||||
v-model="stripe.paymentDescription"
|
||||
:placeholder="$t('Describe in short which methods user can pay with this payment method...')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
|
||||
<AppInputText :title="$t('Your Webhook URL')" :description="$t('Please copy your url and paste it to the service webhook setup.')">
|
||||
<CopyInput size="small" :str="getWebhookEndpoint('stripe')" />
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('Your Webhook URL')" :description="$t('Please copy your url and paste it to the service webhook setup.')">
|
||||
<CopyInput size="small" :str="getWebhookEndpoint('stripe')" />
|
||||
</AppInputText>
|
||||
|
||||
<div @click="stripe.isVisibleCredentialsForm = !stripe.isVisibleCredentialsForm" class="flex items-center cursor-pointer" :class="{'mb-4': stripe.isVisibleCredentialsForm}">
|
||||
<edit2-icon size="14" class="vue-feather text-theme mr-2.5" />
|
||||
<b class="text-sm">{{ $t('Update Your Credentials') }}</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@click="stripe.isVisibleCredentialsForm = !stripe.isVisibleCredentialsForm"
|
||||
class="flex cursor-pointer items-center"
|
||||
:class="{ 'mb-4': stripe.isVisibleCredentialsForm }"
|
||||
>
|
||||
<edit2-icon size="14" class="vue-feather text-theme mr-2.5" />
|
||||
<b class="text-sm">{{ $t('Update Your Credentials') }}</b>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Set up Stripe credentials-->
|
||||
<ValidationObserver
|
||||
v-if="! stripe.isConfigured || stripe.isVisibleCredentialsForm"
|
||||
@submit.prevent="storeCredentials('stripe')"
|
||||
ref="credentialsForm"
|
||||
v-slot="{ invalid }"
|
||||
tag="form"
|
||||
class="p-5 shadow-lg rounded-xl"
|
||||
>
|
||||
<FormLabel v-if="! stripe.isConfigured" icon="shield">
|
||||
{{ $t('Configure Your Credentials') }}
|
||||
</FormLabel>
|
||||
<ValidationProvider tag="div" mode="passive" name="Publishable Key" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_settings.payments.stripe_pub_key')" :error="errors[0]">
|
||||
<input v-model="stripe.credentials.key" :placeholder="$t('admin_settings.payments.stripe_pub_key_plac')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="Secret Key" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_settings.payments.stripe_sec_key')" :error="errors[0]">
|
||||
<input v-model="stripe.credentials.secret" :placeholder="$t('admin_settings.payments.stripe_sec_key_plac')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="Webhook Secret" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Webhook Secret')" :error="errors[0]">
|
||||
<input v-model="stripe.credentials.webhook" :placeholder="$t('Paste your webhook secret')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<!--Set up Stripe credentials-->
|
||||
<ValidationObserver
|
||||
v-if="!stripe.isConfigured || stripe.isVisibleCredentialsForm"
|
||||
@submit.prevent="storeCredentials('stripe')"
|
||||
ref="credentialsForm"
|
||||
v-slot="{ invalid }"
|
||||
tag="form"
|
||||
class="rounded-xl p-5 shadow-lg"
|
||||
>
|
||||
<FormLabel v-if="!stripe.isConfigured" icon="shield">
|
||||
{{ $t('Configure Your Credentials') }}
|
||||
</FormLabel>
|
||||
<ValidationProvider tag="div" mode="passive" name="Publishable Key" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_settings.payments.stripe_pub_key')" :error="errors[0]">
|
||||
<input
|
||||
v-model="stripe.credentials.key"
|
||||
:placeholder="$t('admin_settings.payments.stripe_pub_key_plac')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="Secret Key" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_settings.payments.stripe_sec_key')" :error="errors[0]">
|
||||
<input
|
||||
v-model="stripe.credentials.secret"
|
||||
:placeholder="$t('admin_settings.payments.stripe_sec_key_plac')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="Webhook Secret" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Webhook Secret')" :error="errors[0]">
|
||||
<input
|
||||
v-model="stripe.credentials.webhook"
|
||||
:placeholder="$t('Paste your webhook secret')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<ButtonBase :disabled="isLoading" :loading="isLoading" button-style="theme" type="submit" class="w-full">
|
||||
{{ $t('Store Credentials') }}
|
||||
</ButtonBase>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
</div>
|
||||
<ButtonBase :disabled="isLoading" :loading="isLoading" button-style="theme" type="submit" class="w-full">
|
||||
{{ $t('Store Credentials') }}
|
||||
</ButtonBase>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Paystack method configuration-->
|
||||
<div v-if="allowedPayments" class="card shadow-card">
|
||||
<img :src="$getPaymentLogo('paystack')" alt="Paystack" class="mb-8 h-7">
|
||||
<!--Paystack method configuration-->
|
||||
<div v-if="allowedPayments" class="card shadow-card">
|
||||
<img :src="$getPaymentLogo('paystack')" alt="Paystack" class="mb-8 h-7" />
|
||||
|
||||
<AppInputSwitch :title="$t('Allow Paystack Service')" :description="$t('Allow your users pay by their credit card')" :is-last="! paystack.allowedService">
|
||||
<SwitchInput @input="$updateText('/admin/settings', 'allowed_paystack', paystack.allowedService)" v-model="paystack.allowedService" :state="paystack.allowedService" />
|
||||
</AppInputSwitch>
|
||||
<AppInputSwitch :title="$t('Allow Paystack Service')" :description="$t('Allow your users pay by their credit card')" :is-last="!paystack.allowedService">
|
||||
<SwitchInput
|
||||
@input="$updateText('/admin/settings', 'allowed_paystack', paystack.allowedService)"
|
||||
v-model="paystack.allowedService"
|
||||
:state="paystack.allowedService"
|
||||
/>
|
||||
</AppInputSwitch>
|
||||
|
||||
<!--Paystack credentials are set up-->
|
||||
<div v-if="paystack.allowedService">
|
||||
<div v-if="paystack.isConfigured">
|
||||
<AppInputText @input="$updateText('/admin/settings', 'paystack_payment_description', paystack.paymentDescription)" :title="$t('Payment Description')" :description="$t('The description showed below user payment method selection.')">
|
||||
<textarea rows="2" @input="$updateText('/admin/settings', 'paystack_payment_description', paystack.paymentDescription, true)" v-model="paystack.paymentDescription" :placeholder="$t('Describe in short which methods user can pay with this payment method...')" type="text" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
<!--Paystack credentials are set up-->
|
||||
<div v-if="paystack.allowedService">
|
||||
<div v-if="paystack.isConfigured">
|
||||
<AppInputText
|
||||
@input="$updateText('/admin/settings', 'paystack_payment_description', paystack.paymentDescription)"
|
||||
:title="$t('Payment Description')"
|
||||
:description="$t('The description showed below user payment method selection.')"
|
||||
>
|
||||
<textarea
|
||||
rows="2"
|
||||
@input="$updateText('/admin/settings', 'paystack_payment_description', paystack.paymentDescription, true)"
|
||||
v-model="paystack.paymentDescription"
|
||||
:placeholder="$t('Describe in short which methods user can pay with this payment method...')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
|
||||
<AppInputText :title="$t('Your Webhook URL')" :description="$t('Please copy your url and paste it to the service webhook setup.')">
|
||||
<CopyInput size="small" :str="getWebhookEndpoint('paystack')" />
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('Your Webhook URL')" :description="$t('Please copy your url and paste it to the service webhook setup.')">
|
||||
<CopyInput size="small" :str="getWebhookEndpoint('paystack')" />
|
||||
</AppInputText>
|
||||
|
||||
<div @click="paystack.isVisibleCredentialsForm = !paystack.isVisibleCredentialsForm" class="flex items-center cursor-pointer" :class="{'mb-4': paystack.isVisibleCredentialsForm}">
|
||||
<edit2-icon size="14" class="vue-feather text-theme mr-2.5" />
|
||||
<b class="text-sm">{{ $t('Update Your Credentials') }}</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@click="paystack.isVisibleCredentialsForm = !paystack.isVisibleCredentialsForm"
|
||||
class="flex cursor-pointer items-center"
|
||||
:class="{ 'mb-4': paystack.isVisibleCredentialsForm }"
|
||||
>
|
||||
<edit2-icon size="14" class="vue-feather text-theme mr-2.5" />
|
||||
<b class="text-sm">{{ $t('Update Your Credentials') }}</b>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Set up Paystack credentials-->
|
||||
<ValidationObserver
|
||||
v-if="! paystack.isConfigured || paystack.isVisibleCredentialsForm"
|
||||
@submit.prevent="storeCredentials('paystack')"
|
||||
ref="credentialsForm"
|
||||
v-slot="{ invalid }"
|
||||
tag="form"
|
||||
class="p-5 shadow-lg rounded-xl"
|
||||
>
|
||||
<FormLabel v-if="! paystack.isConfigured" icon="shield">
|
||||
{{ $t('Configure Your Credentials') }}
|
||||
</FormLabel>
|
||||
<ValidationProvider tag="div" mode="passive" name="Publishable Key" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_settings.payments.stripe_pub_key')" :error="errors[0]">
|
||||
<input v-model="paystack.credentials.key" :placeholder="$t('admin_settings.payments.stripe_pub_key_plac')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="Secret Key" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_settings.payments.stripe_sec_key')" :error="errors[0]">
|
||||
<input v-model="paystack.credentials.secret" :placeholder="$t('admin_settings.payments.stripe_sec_key_plac')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<!--Set up Paystack credentials-->
|
||||
<ValidationObserver
|
||||
v-if="!paystack.isConfigured || paystack.isVisibleCredentialsForm"
|
||||
@submit.prevent="storeCredentials('paystack')"
|
||||
ref="credentialsForm"
|
||||
v-slot="{ invalid }"
|
||||
tag="form"
|
||||
class="rounded-xl p-5 shadow-lg"
|
||||
>
|
||||
<FormLabel v-if="!paystack.isConfigured" icon="shield">
|
||||
{{ $t('Configure Your Credentials') }}
|
||||
</FormLabel>
|
||||
<ValidationProvider tag="div" mode="passive" name="Publishable Key" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_settings.payments.stripe_pub_key')" :error="errors[0]">
|
||||
<input
|
||||
v-model="paystack.credentials.key"
|
||||
:placeholder="$t('admin_settings.payments.stripe_pub_key_plac')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="Secret Key" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_settings.payments.stripe_sec_key')" :error="errors[0]">
|
||||
<input
|
||||
v-model="paystack.credentials.secret"
|
||||
:placeholder="$t('admin_settings.payments.stripe_sec_key_plac')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<ButtonBase :disabled="isLoading" :loading="isLoading" button-style="theme" type="submit" class="w-full">
|
||||
{{ $t('Store Credentials') }}
|
||||
</ButtonBase>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
</div>
|
||||
<ButtonBase :disabled="isLoading" :loading="isLoading" button-style="theme" type="submit" class="w-full">
|
||||
{{ $t('Store Credentials') }}
|
||||
</ButtonBase>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--PayPal method configuration-->
|
||||
<div v-if="allowedPayments" class="card shadow-card">
|
||||
<img :src="$getPaymentLogo('paypal')" alt="PayPal" class="mb-8 h-8">
|
||||
<!--PayPal method configuration-->
|
||||
<div v-if="allowedPayments" class="card shadow-card">
|
||||
<img :src="$getPaymentLogo('paypal')" alt="PayPal" class="mb-8 h-8" />
|
||||
|
||||
<AppInputSwitch :title="$t('Allow PayPal Service')" :description="$t('Allow your users pay by their credit card')" :is-last="! paypal.allowedService">
|
||||
<SwitchInput @input="$updateText('/admin/settings', 'allowed_paypal', paypal.allowedService)" v-model="paypal.allowedService" :state="paypal.allowedService" />
|
||||
</AppInputSwitch>
|
||||
<AppInputSwitch :title="$t('Allow PayPal Service')" :description="$t('Allow your users pay by their credit card')" :is-last="!paypal.allowedService">
|
||||
<SwitchInput @input="$updateText('/admin/settings', 'allowed_paypal', paypal.allowedService)" v-model="paypal.allowedService" :state="paypal.allowedService" />
|
||||
</AppInputSwitch>
|
||||
|
||||
<!--Stripe credentials are set up-->
|
||||
<div v-if="paypal.allowedService">
|
||||
<div v-if="paypal.isConfigured">
|
||||
<AppInputSwitch :title="$t('Live Mode')" :description="$t('Toggle amid live and sandbox mode')">
|
||||
<SwitchInput @input="$updateText('/admin/settings', 'paypal_live', config.isPayPalLive)" v-model="config.isPayPalLive" :state="config.isPayPalLive" />
|
||||
</AppInputSwitch>
|
||||
<!--Stripe credentials are set up-->
|
||||
<div v-if="paypal.allowedService">
|
||||
<div v-if="paypal.isConfigured">
|
||||
<AppInputSwitch :title="$t('Live Mode')" :description="$t('Toggle amid live and sandbox mode')">
|
||||
<SwitchInput @input="$updateText('/admin/settings', 'paypal_live', config.isPayPalLive)" v-model="config.isPayPalLive" :state="config.isPayPalLive" />
|
||||
</AppInputSwitch>
|
||||
|
||||
<AppInputText @input="$updateText('/admin/settings', 'paypal_payment_description', paypal.paymentDescription)" :title="$t('Payment Description')" :description="$t('The description showed below user payment method selection.')">
|
||||
<textarea rows="2" @input="$updateText('/admin/settings', 'paypal_payment_description', paypal.paymentDescription, true)" v-model="paypal.paymentDescription" :placeholder="$t('Describe in short which methods user can pay with this payment method...')" type="text" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
<AppInputText
|
||||
@input="$updateText('/admin/settings', 'paypal_payment_description', paypal.paymentDescription)"
|
||||
:title="$t('Payment Description')"
|
||||
:description="$t('The description showed below user payment method selection.')"
|
||||
>
|
||||
<textarea
|
||||
rows="2"
|
||||
@input="$updateText('/admin/settings', 'paypal_payment_description', paypal.paymentDescription, true)"
|
||||
v-model="paypal.paymentDescription"
|
||||
:placeholder="$t('Describe in short which methods user can pay with this payment method...')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
|
||||
<AppInputText :title="$t('Your Webhook URL')" :description="$t('Please copy your url and paste it to the service webhook setup.')">
|
||||
<CopyInput size="small" :str="getWebhookEndpoint('paypal')" />
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('Your Webhook URL')" :description="$t('Please copy your url and paste it to the service webhook setup.')">
|
||||
<CopyInput size="small" :str="getWebhookEndpoint('paypal')" />
|
||||
</AppInputText>
|
||||
|
||||
<div @click="paypal.isVisibleCredentialsForm = !paypal.isVisibleCredentialsForm" class="flex items-center cursor-pointer" :class="{'mb-4': paypal.isVisibleCredentialsForm}">
|
||||
<edit2-icon size="14" class="vue-feather text-theme mr-2.5" />
|
||||
<b class="text-sm">{{ $t('Update Your Credentials') }}</b>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@click="paypal.isVisibleCredentialsForm = !paypal.isVisibleCredentialsForm"
|
||||
class="flex cursor-pointer items-center"
|
||||
:class="{ 'mb-4': paypal.isVisibleCredentialsForm }"
|
||||
>
|
||||
<edit2-icon size="14" class="vue-feather text-theme mr-2.5" />
|
||||
<b class="text-sm">{{ $t('Update Your Credentials') }}</b>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Set up Paypal credentials-->
|
||||
<ValidationObserver
|
||||
v-if="! paypal.isConfigured || paypal.isVisibleCredentialsForm"
|
||||
@submit.prevent="storeCredentials('paypal')"
|
||||
ref="credentialsForm"
|
||||
v-slot="{ invalid }"
|
||||
tag="form"
|
||||
class="p-5 shadow-lg rounded-xl"
|
||||
>
|
||||
<FormLabel v-if="! paypal.isConfigured" icon="shield">
|
||||
{{ $t('Configure Your Credentials') }}
|
||||
</FormLabel>
|
||||
<ValidationProvider tag="div" mode="passive" name="Publishable Key" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_settings.payments.stripe_pub_key')" :error="errors[0]">
|
||||
<input v-model="paypal.credentials.key" :placeholder="$t('admin_settings.payments.stripe_pub_key_plac')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="Secret Key" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_settings.payments.stripe_sec_key')" :error="errors[0]">
|
||||
<input v-model="paypal.credentials.secret" :placeholder="$t('admin_settings.payments.stripe_sec_key_plac')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="Webhook ID" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Webhook ID')" :error="errors[0]">
|
||||
<input v-model="paypal.credentials.webhook" :placeholder="$t('Paste your webhook id')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<!--Set up Paypal credentials-->
|
||||
<ValidationObserver
|
||||
v-if="!paypal.isConfigured || paypal.isVisibleCredentialsForm"
|
||||
@submit.prevent="storeCredentials('paypal')"
|
||||
ref="credentialsForm"
|
||||
v-slot="{ invalid }"
|
||||
tag="form"
|
||||
class="rounded-xl p-5 shadow-lg"
|
||||
>
|
||||
<FormLabel v-if="!paypal.isConfigured" icon="shield">
|
||||
{{ $t('Configure Your Credentials') }}
|
||||
</FormLabel>
|
||||
<ValidationProvider tag="div" mode="passive" name="Publishable Key" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_settings.payments.stripe_pub_key')" :error="errors[0]">
|
||||
<input
|
||||
v-model="paypal.credentials.key"
|
||||
:placeholder="$t('admin_settings.payments.stripe_pub_key_plac')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="Secret Key" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_settings.payments.stripe_sec_key')" :error="errors[0]">
|
||||
<input
|
||||
v-model="paypal.credentials.secret"
|
||||
:placeholder="$t('admin_settings.payments.stripe_sec_key_plac')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="Webhook ID" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Webhook ID')" :error="errors[0]">
|
||||
<input
|
||||
v-model="paypal.credentials.webhook"
|
||||
:placeholder="$t('Paste your webhook id')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<ButtonBase :disabled="isLoading" :loading="isLoading" button-style="theme" type="submit" class="w-full">
|
||||
{{ $t('Store Credentials') }}
|
||||
</ButtonBase>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
</div>
|
||||
</PageTab>
|
||||
<ButtonBase :disabled="isLoading" :loading="isLoading" button-style="theme" type="submit" class="w-full">
|
||||
{{ $t('Store Credentials') }}
|
||||
</ButtonBase>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
</div>
|
||||
</PageTab>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
Edit2Icon, Trash2Icon,
|
||||
} from 'vue-feather-icons'
|
||||
import AppInputButton from "../../../../components/Admin/AppInputButton";
|
||||
import DatatableWrapper from "../../../../components/Others/Tables/DatatableWrapper";
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import PageTabGroup from "../../../../components/Others/Layout/PageTabGroup";
|
||||
import SelectInput from "../../../../components/Others/Forms/SelectInput";
|
||||
import SwitchInput from "../../../../components/Others/Forms/SwitchInput";
|
||||
import ImageInput from "../../../../components/Others/Forms/ImageInput";
|
||||
import AppInputSwitch from "../../../../components/Admin/AppInputSwitch"
|
||||
import FormLabel from "../../../../components/Others/Forms/FormLabel";
|
||||
import ButtonBase from "../../../../components/FilesView/ButtonBase";
|
||||
import CopyInput from "../../../../components/Others/Forms/CopyInput"
|
||||
import SetupBox from "../../../../components/Others/Forms/SetupBox";
|
||||
import AppInputText from "../../../../components/Admin/AppInputText"
|
||||
import PageTab from "../../../../components/Others/Layout/PageTab";
|
||||
import InfoBox from "../../../../components/Others/Forms/InfoBox";
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {events} from '../../../../bus'
|
||||
import {mapGetters} from 'vuex'
|
||||
import axios from 'axios'
|
||||
import { Edit2Icon, Trash2Icon } from 'vue-feather-icons'
|
||||
import AppInputButton from '../../../../components/Admin/AppInputButton'
|
||||
import DatatableWrapper from '../../../../components/Others/Tables/DatatableWrapper'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import PageTabGroup from '../../../../components/Others/Layout/PageTabGroup'
|
||||
import SelectInput from '../../../../components/Others/Forms/SelectInput'
|
||||
import SwitchInput from '../../../../components/Others/Forms/SwitchInput'
|
||||
import ImageInput from '../../../../components/Others/Forms/ImageInput'
|
||||
import AppInputSwitch from '../../../../components/Admin/AppInputSwitch'
|
||||
import FormLabel from '../../../../components/Others/Forms/FormLabel'
|
||||
import ButtonBase from '../../../../components/FilesView/ButtonBase'
|
||||
import CopyInput from '../../../../components/Others/Forms/CopyInput'
|
||||
import SetupBox from '../../../../components/Others/Forms/SetupBox'
|
||||
import AppInputText from '../../../../components/Admin/AppInputText'
|
||||
import PageTab from '../../../../components/Others/Layout/PageTab'
|
||||
import InfoBox from '../../../../components/Others/Forms/InfoBox'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { events } from '../../../../bus'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'AppPayments',
|
||||
components: {
|
||||
AppInputButton,
|
||||
DatatableWrapper,
|
||||
ValidationObserver,
|
||||
ValidationProvider,
|
||||
AppInputSwitch,
|
||||
AppInputText,
|
||||
PageTabGroup,
|
||||
SwitchInput,
|
||||
SelectInput,
|
||||
ImageInput,
|
||||
ButtonBase,
|
||||
CopyInput,
|
||||
FormLabel,
|
||||
Trash2Icon,
|
||||
Edit2Icon,
|
||||
SetupBox,
|
||||
required,
|
||||
PageTab,
|
||||
InfoBox,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'subscriptionTypes',
|
||||
'config',
|
||||
]),
|
||||
submitButtonText() {
|
||||
return this.isLoading ? this.$t('admin_settings.payments.button_testing') : this.$t('admin_settings.payments.button_submit')
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
allowedRegistrationBonus: true,
|
||||
registrationBonusAmount: undefined,
|
||||
export default {
|
||||
name: 'AppPayments',
|
||||
components: {
|
||||
AppInputButton,
|
||||
DatatableWrapper,
|
||||
ValidationObserver,
|
||||
ValidationProvider,
|
||||
AppInputSwitch,
|
||||
AppInputText,
|
||||
PageTabGroup,
|
||||
SwitchInput,
|
||||
SelectInput,
|
||||
ImageInput,
|
||||
ButtonBase,
|
||||
CopyInput,
|
||||
FormLabel,
|
||||
Trash2Icon,
|
||||
Edit2Icon,
|
||||
SetupBox,
|
||||
required,
|
||||
PageTab,
|
||||
InfoBox,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['subscriptionTypes', 'config']),
|
||||
submitButtonText() {
|
||||
return this.isLoading ? this.$t('admin_settings.payments.button_testing') : this.$t('admin_settings.payments.button_submit')
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
allowedRegistrationBonus: true,
|
||||
registrationBonusAmount: undefined,
|
||||
|
||||
allowedPayments: false,
|
||||
allowedPayments: false,
|
||||
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
errorMessage: '',
|
||||
stripe: {
|
||||
allowedService: true,
|
||||
isConfigured: false,
|
||||
isVisibleCredentialsForm: false,
|
||||
paymentDescription: undefined,
|
||||
credentials: {
|
||||
key: undefined,
|
||||
secret: undefined,
|
||||
webhook: undefined,
|
||||
}
|
||||
},
|
||||
paystack: {
|
||||
allowedService: true,
|
||||
isConfigured: false,
|
||||
isVisibleCredentialsForm: false,
|
||||
paymentDescription: undefined,
|
||||
credentials: {
|
||||
key: undefined,
|
||||
secret: undefined,
|
||||
}
|
||||
},
|
||||
paypal: {
|
||||
allowedService: true,
|
||||
isConfigured: false,
|
||||
isVisibleCredentialsForm: false,
|
||||
paymentDescription: undefined,
|
||||
credentials: {
|
||||
key: undefined,
|
||||
secret: undefined,
|
||||
webhook: undefined,
|
||||
}
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
label: this.$t('Name'),
|
||||
field: 'name',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('Currency'),
|
||||
field: 'currency',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('Interval'),
|
||||
field: 'interval',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_plans.table.subscribers'),
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
sortable: false
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async storeCredentials(service) {
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
errorMessage: '',
|
||||
stripe: {
|
||||
allowedService: true,
|
||||
isConfigured: false,
|
||||
isVisibleCredentialsForm: false,
|
||||
paymentDescription: undefined,
|
||||
credentials: {
|
||||
key: undefined,
|
||||
secret: undefined,
|
||||
webhook: undefined,
|
||||
},
|
||||
},
|
||||
paystack: {
|
||||
allowedService: true,
|
||||
isConfigured: false,
|
||||
isVisibleCredentialsForm: false,
|
||||
paymentDescription: undefined,
|
||||
credentials: {
|
||||
key: undefined,
|
||||
secret: undefined,
|
||||
},
|
||||
},
|
||||
paypal: {
|
||||
allowedService: true,
|
||||
isConfigured: false,
|
||||
isVisibleCredentialsForm: false,
|
||||
paymentDescription: undefined,
|
||||
credentials: {
|
||||
key: undefined,
|
||||
secret: undefined,
|
||||
webhook: undefined,
|
||||
},
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
label: this.$t('Name'),
|
||||
field: 'name',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('Currency'),
|
||||
field: 'currency',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('Interval'),
|
||||
field: 'interval',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_plans.table.subscribers'),
|
||||
sortable: false,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
sortable: false,
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async storeCredentials(service) {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.credentialsForm.validate()
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.credentialsForm.validate();
|
||||
if (!isValid) return
|
||||
|
||||
if (!isValid) return;
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/admin/settings/payment-service', {
|
||||
service: service,
|
||||
key: this[service].credentials.key,
|
||||
secret: this[service].credentials.secret,
|
||||
webhook: this[service].credentials.webhook || undefined,
|
||||
})
|
||||
.then(() => {
|
||||
// Update Credentials
|
||||
let commitKey = {
|
||||
stripe: 'SET_STRIPE_CREDENTIALS',
|
||||
paystack: 'SET_PAYSTACK_CREDENTIALS',
|
||||
paypal: 'SET_PAYPAL_CREDENTIALS',
|
||||
}[service]
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/admin/settings/payment-service', {
|
||||
service: service,
|
||||
key: this[service].credentials.key,
|
||||
secret: this[service].credentials.secret,
|
||||
webhook: this[service].credentials.webhook || undefined,
|
||||
})
|
||||
.then(() => {
|
||||
// Commit credentials
|
||||
this.$store.commit(commitKey, this[service].credentials)
|
||||
|
||||
// Update Credentials
|
||||
let commitKey = {
|
||||
stripe: 'SET_STRIPE_CREDENTIALS',
|
||||
paystack: 'SET_PAYSTACK_CREDENTIALS',
|
||||
paypal: 'SET_PAYPAL_CREDENTIALS',
|
||||
}[service]
|
||||
this[service].allowedService = true
|
||||
this[service].isConfigured = true
|
||||
this[service].isVisibleCredentialsForm = false
|
||||
|
||||
// Commit credentials
|
||||
this.$store.commit(commitKey, this[service].credentials)
|
||||
// Show toaster
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.credentials_set', {
|
||||
service: service,
|
||||
}),
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response.status === 500) {
|
||||
this.isError = true
|
||||
this.errorMessage = error.response.data.message
|
||||
}
|
||||
})
|
||||
.finally(() => (this.isLoading = false))
|
||||
},
|
||||
subscriptionTypeChange(type) {
|
||||
events.$emit('confirm:open', {
|
||||
title: this.$t('Are you sure you want to change subscription type?'),
|
||||
message: this.$t(
|
||||
'We strongly do not recommend change this value if there is any subscribed user to prevent any failures. You can operate only with one type of subscription and you can not change it on the fly!'
|
||||
),
|
||||
action: {
|
||||
type: type,
|
||||
operation: 'change-subscription-type',
|
||||
},
|
||||
})
|
||||
},
|
||||
getWebhookEndpoint(service) {
|
||||
return `${this.config.host}/api/subscriptions/${service}/webhook`
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// Set payment description
|
||||
this.stripe.paymentDescription = this.config.stripe_payment_description
|
||||
this.paystack.paymentDescription = this.config.paystack_payment_description
|
||||
this.paypal.paymentDescription = this.config.paypal_payment_description
|
||||
|
||||
this[service].allowedService = true
|
||||
this[service].isConfigured = true
|
||||
this[service].isVisibleCredentialsForm = false
|
||||
// Set if service is allowed
|
||||
this.stripe.allowedService = this.config.isStripe
|
||||
this.paystack.allowedService = this.config.isPaystack
|
||||
this.paypal.allowedService = this.config.isPayPal
|
||||
|
||||
// Show toaster
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.credentials_set', {service: service}),
|
||||
})
|
||||
})
|
||||
.catch(error => {
|
||||
if (this.config.stripe_public_key) this.stripe.isConfigured = true
|
||||
|
||||
if (error.response.status === 500) {
|
||||
this.isError = true
|
||||
this.errorMessage = error.response.data.message
|
||||
}
|
||||
})
|
||||
.finally(() => this.isLoading = false)
|
||||
},
|
||||
subscriptionTypeChange(type) {
|
||||
events.$emit('confirm:open', {
|
||||
title: this.$t('Are you sure you want to change subscription type?'),
|
||||
message: this.$t('We strongly do not recommend change this value if there is any subscribed user to prevent any failures. You can operate only with one type of subscription and you can not change it on the fly!'),
|
||||
action: {
|
||||
type: type,
|
||||
operation: 'change-subscription-type',
|
||||
}
|
||||
})
|
||||
},
|
||||
getWebhookEndpoint(service) {
|
||||
return `${this.config.host}/api/subscriptions/${service}/webhook`
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// Set payment description
|
||||
this.stripe.paymentDescription = this.config.stripe_payment_description
|
||||
this.paystack.paymentDescription = this.config.paystack_payment_description
|
||||
this.paypal.paymentDescription = this.config.paypal_payment_description
|
||||
if (this.config.paystack_public_key) this.paystack.isConfigured = true
|
||||
|
||||
// Set if service is allowed
|
||||
this.stripe.allowedService = this.config.isStripe
|
||||
this.paystack.allowedService = this.config.isPaystack
|
||||
this.paypal.allowedService = this.config.isPayPal
|
||||
if (this.config.paypal_client_id) this.paypal.isConfigured = true
|
||||
|
||||
if (this.config.stripe_public_key)
|
||||
this.stripe.isConfigured = true
|
||||
this.allowedPayments = this.config.allowed_payments
|
||||
|
||||
if (this.config.paystack_public_key)
|
||||
this.paystack.isConfigured = true
|
||||
|
||||
if (this.config.paypal_client_id)
|
||||
this.paypal.isConfigured = true
|
||||
|
||||
this.allowedPayments = this.config.allowed_payments
|
||||
|
||||
// Set metered
|
||||
this.allowedRegistrationBonus = this.config.allowed_registration_bonus
|
||||
this.registrationBonusAmount = this.config.registration_bonus_amount
|
||||
},
|
||||
created() {
|
||||
events.$on('action:confirmed', data => {
|
||||
if (data.operation === 'change-subscription-type')
|
||||
this.$updateText('/admin/settings', 'subscription_type', data.type)
|
||||
})
|
||||
},
|
||||
destroyed() {
|
||||
events.$off('action:confirmed')
|
||||
},
|
||||
}
|
||||
// Set metered
|
||||
this.allowedRegistrationBonus = this.config.allowed_registration_bonus
|
||||
this.registrationBonusAmount = this.config.registration_bonus_amount
|
||||
},
|
||||
created() {
|
||||
events.$on('action:confirmed', (data) => {
|
||||
if (data.operation === 'change-subscription-type') this.$updateText('/admin/settings', 'subscription_type', data.type)
|
||||
})
|
||||
},
|
||||
destroyed() {
|
||||
events.$off('action:confirmed')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,103 +1,137 @@
|
||||
<template>
|
||||
<div>
|
||||
<!--Plans-->
|
||||
<div v-if="! config.isEmptyPlans" class="card shadow-card">
|
||||
<!--Plans-->
|
||||
<div v-if="!config.isEmptyPlans" class="card shadow-card">
|
||||
<!--Create button-->
|
||||
<div v-if="!config.isCreatedMeteredPlan || config.subscriptionType === 'fixed'" class="mb-6">
|
||||
<router-link :to="{ name: createPlanRoute }">
|
||||
<MobileActionButton icon="plus">
|
||||
{{ $t('admin_page_plans.create_plan_button') }}
|
||||
</MobileActionButton>
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
<!--Create button-->
|
||||
<div v-if="! config.isCreatedMeteredPlan || config.subscriptionType === 'fixed'" class="mb-6">
|
||||
<router-link :to="{name: createPlanRoute}">
|
||||
<MobileActionButton icon="plus">
|
||||
{{ $t('admin_page_plans.create_plan_button') }}
|
||||
</MobileActionButton>
|
||||
</router-link>
|
||||
</div>
|
||||
|
||||
<!--Datatable-->
|
||||
<!--Datatable-->
|
||||
<DatatableWrapper @data="plans = $event" @init="isLoading = false" api="/api/subscriptions/admin/plans" :paginator="true" :columns="columns" class="overflow-x-auto">
|
||||
<template slot-scope="{ row }">
|
||||
|
||||
<!--Metered subscription-->
|
||||
<tr v-if="config.subscriptionType === 'metered'" class="border-b dark:border-opacity-5 border-light border-dashed whitespace-nowrap">
|
||||
<td class="py-5 md:pr-1 pr-3">
|
||||
<router-link class="text-sm font-bold" :to="{name: 'PlanMeteredSettings', params: {id: row.data.id}}">
|
||||
{{ row.data.attributes.name }}
|
||||
</router-link>
|
||||
<!--Metered subscription-->
|
||||
<tr v-if="config.subscriptionType === 'metered'" class="whitespace-nowrap border-b border-dashed border-light dark:border-opacity-5">
|
||||
<td class="py-5 pr-3 md:pr-1">
|
||||
<router-link
|
||||
class="text-sm font-bold"
|
||||
:to="{
|
||||
name: 'PlanMeteredSettings',
|
||||
params: { id: row.data.id },
|
||||
}"
|
||||
>
|
||||
{{ row.data.attributes.name }}
|
||||
</router-link>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<ColorLabel :color="$getPlanStatusColor(row.data.attributes.status)">
|
||||
{{ row.data.attributes.status }}
|
||||
</ColorLabel>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<td class="px-3 md:px-1">
|
||||
<ColorLabel :color="$getPlanStatusColor(row.data.attributes.status)">
|
||||
{{ row.data.attributes.status }}
|
||||
</ColorLabel>
|
||||
</td>
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="text-sm font-bold">
|
||||
{{ row.data.attributes.currency }}
|
||||
{{ row.data.attributes.currency }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="text-sm font-bold capitalize">
|
||||
{{ row.data.attributes.interval }}
|
||||
{{ row.data.attributes.interval }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="text-sm font-bold">
|
||||
{{ row.data.attributes.subscribers }}
|
||||
{{ row.data.attributes.subscribers }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:pl-1 pl-3 text-right">
|
||||
<div class="flex space-x-2 w-full justify-end">
|
||||
<td class="pl-3 text-right md:pl-1">
|
||||
<div class="flex w-full justify-end space-x-2">
|
||||
<router-link
|
||||
:to="{name: 'PlanMeteredSettings', params: {id: row.data.id}}"
|
||||
class="flex items-center justify-center w-8 h-8 rounded-md hover:bg-green-100 dark:bg-2x-dark-foreground bg-light-background transition-colors"
|
||||
>
|
||||
:to="{
|
||||
name: 'PlanMeteredSettings',
|
||||
params: { id: row.data.id },
|
||||
}"
|
||||
class="flex h-8 w-8 items-center justify-center rounded-md bg-light-background transition-colors hover:bg-green-100 dark:bg-2x-dark-foreground"
|
||||
>
|
||||
<Edit2Icon size="15" class="opacity-75" />
|
||||
</router-link>
|
||||
<router-link
|
||||
v-if="row.data.attributes.status !== 'archived'"
|
||||
:to="{name: 'PlanMeteredDelete', params: {id: row.data.id}}"
|
||||
class="flex items-center justify-center w-8 h-8 rounded-md hover:bg-red-100 dark:bg-2x-dark-foreground bg-light-background transition-colors"
|
||||
>
|
||||
v-if="row.data.attributes.status !== 'archived'"
|
||||
:to="{
|
||||
name: 'PlanMeteredDelete',
|
||||
params: { id: row.data.id },
|
||||
}"
|
||||
class="flex h-8 w-8 items-center justify-center rounded-md bg-light-background transition-colors hover:bg-red-100 dark:bg-2x-dark-foreground"
|
||||
>
|
||||
<Trash2Icon size="15" class="opacity-75" />
|
||||
</router-link>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!--Fixed subscription-->
|
||||
<tr v-if="config.subscriptionType === 'fixed'" class="border-b dark:border-opacity-5 border-light border-dashed whitespace-nowrap">
|
||||
<td class="py-5 md:pr-1 pr-3">
|
||||
<SwitchInput @input="$updateInput(`/subscriptions/admin/plans/${row.data.id}`, 'visible', row.data.attributes.visible)" v-model="row.data.attributes.visible" :state="row.data.attributes.visible" class="switch"/>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<router-link class="text-sm font-bold" :to="{name: 'PlanFixedSettings', params: {id: row.data.id}}">
|
||||
{{ row.data.attributes.name }}
|
||||
</router-link>
|
||||
<!--Fixed subscription-->
|
||||
<tr v-if="config.subscriptionType === 'fixed'" class="whitespace-nowrap border-b border-dashed border-light dark:border-opacity-5">
|
||||
<td class="py-5 pr-3 md:pr-1">
|
||||
<SwitchInput
|
||||
@input="$updateInput(`/subscriptions/admin/plans/${row.data.id}`, 'visible', row.data.attributes.visible)"
|
||||
v-model="row.data.attributes.visible"
|
||||
:state="row.data.attributes.visible"
|
||||
class="switch"
|
||||
/>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<td class="px-3 md:px-1">
|
||||
<router-link
|
||||
class="text-sm font-bold"
|
||||
:to="{
|
||||
name: 'PlanFixedSettings',
|
||||
params: { id: row.data.id },
|
||||
}"
|
||||
>
|
||||
{{ row.data.attributes.name }}
|
||||
</router-link>
|
||||
</td>
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="text-sm font-bold">
|
||||
{{ row.data.attributes.price }}
|
||||
{{ row.data.attributes.price }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="text-sm font-bold capitalize">
|
||||
{{ row.data.attributes.interval }}
|
||||
{{ row.data.attributes.interval }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="text-sm font-bold">
|
||||
{{ row.data.attributes.subscribers }}
|
||||
{{ row.data.attributes.subscribers }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="text-sm font-bold">
|
||||
{{ row.data.attributes.features.max_storage_amount }} GB
|
||||
{{ row.data.attributes.features.max_storage_amount }}
|
||||
GB
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:pl-1 pl-3 text-right">
|
||||
<div class="flex space-x-2 w-full justify-end">
|
||||
<router-link class="flex items-center justify-center w-8 h-8 rounded-md hover:bg-green-100 dark:bg-2x-dark-foreground bg-light-background transition-colors" :to="{name: 'PlanFixedSettings', params: {id: row.data.id}}">
|
||||
<td class="pl-3 text-right md:pl-1">
|
||||
<div class="flex w-full justify-end space-x-2">
|
||||
<router-link
|
||||
class="flex h-8 w-8 items-center justify-center rounded-md bg-light-background transition-colors hover:bg-green-100 dark:bg-2x-dark-foreground"
|
||||
:to="{
|
||||
name: 'PlanFixedSettings',
|
||||
params: { id: row.data.id },
|
||||
}"
|
||||
>
|
||||
<Edit2Icon size="15" class="opacity-75" />
|
||||
</router-link>
|
||||
<router-link class="flex items-center justify-center w-8 h-8 rounded-md hover:bg-red-100 dark:bg-2x-dark-foreground bg-light-background transition-colors" :to="{name: 'PlanFixedDelete', params: {id: row.data.id}}">
|
||||
<router-link
|
||||
class="flex h-8 w-8 items-center justify-center rounded-md bg-light-background transition-colors hover:bg-red-100 dark:bg-2x-dark-foreground"
|
||||
:to="{
|
||||
name: 'PlanFixedDelete',
|
||||
params: { id: row.data.id },
|
||||
}"
|
||||
>
|
||||
<Trash2Icon size="15" class="opacity-75" />
|
||||
</router-link>
|
||||
</div>
|
||||
@@ -105,129 +139,127 @@
|
||||
</tr>
|
||||
</template>
|
||||
</DatatableWrapper>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Empty State-->
|
||||
<div v-if="config.isEmptyPlans" class="flex items-center justify-center h-full">
|
||||
<div class="text-center">
|
||||
<img class="w-28 inline-block mb-6" src="https://twemoji.maxcdn.com/v/13.1.0/svg/1f9fe.svg" alt="transaction">
|
||||
<!--Empty State-->
|
||||
<div v-if="config.isEmptyPlans" class="flex h-full items-center justify-center">
|
||||
<div class="text-center">
|
||||
<img class="mb-6 inline-block w-28" src="https://twemoji.maxcdn.com/v/13.1.0/svg/1f9fe.svg" alt="transaction" />
|
||||
|
||||
<h1 class="text-2xl font-bold mb-1">
|
||||
{{ $t("There is Nothing") }}
|
||||
</h1>
|
||||
<h1 class="mb-1 text-2xl font-bold">
|
||||
{{ $t('There is Nothing') }}
|
||||
</h1>
|
||||
|
||||
<p class="text-sm text-gray-600">
|
||||
{{ $t('All your plans will be visible here') }}
|
||||
</p>
|
||||
<p class="text-sm text-gray-600">
|
||||
{{ $t('All your plans will be visible here') }}
|
||||
</p>
|
||||
|
||||
<router-link :to="{name: createPlanRoute}" class="inline-block mt-6">
|
||||
<ButtonBase class="action-confirm" button-style="theme">
|
||||
{{ $t('Create First Plan') }}
|
||||
</ButtonBase>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
<router-link :to="{ name: createPlanRoute }" class="mt-6 inline-block">
|
||||
<ButtonBase class="action-confirm" button-style="theme">
|
||||
{{ $t('Create First Plan') }}
|
||||
</ButtonBase>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import DatatableWrapper from "../../components/Others/Tables/DatatableWrapper";
|
||||
import MobileActionButton from "../../components/FilesView/MobileActionButton";
|
||||
import SwitchInput from "../../components/Others/Forms/SwitchInput";
|
||||
import ButtonBase from "../../components/FilesView/ButtonBase";
|
||||
import ColorLabel from "../../components/Others/ColorLabel";
|
||||
import {Trash2Icon, Edit2Icon} from "vue-feather-icons";
|
||||
import { mapGetters } from 'vuex'
|
||||
import DatatableWrapper from '../../components/Others/Tables/DatatableWrapper'
|
||||
import MobileActionButton from '../../components/FilesView/MobileActionButton'
|
||||
import SwitchInput from '../../components/Others/Forms/SwitchInput'
|
||||
import ButtonBase from '../../components/FilesView/ButtonBase'
|
||||
import ColorLabel from '../../components/Others/ColorLabel'
|
||||
import { Trash2Icon, Edit2Icon } from 'vue-feather-icons'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Plans',
|
||||
components: {
|
||||
MobileActionButton,
|
||||
DatatableWrapper,
|
||||
SwitchInput,
|
||||
ColorLabel,
|
||||
Trash2Icon,
|
||||
ButtonBase,
|
||||
Edit2Icon,
|
||||
export default {
|
||||
name: 'Plans',
|
||||
components: {
|
||||
MobileActionButton,
|
||||
DatatableWrapper,
|
||||
SwitchInput,
|
||||
ColorLabel,
|
||||
Trash2Icon,
|
||||
ButtonBase,
|
||||
Edit2Icon,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
createPlanRoute() {
|
||||
return {
|
||||
metered: 'CreateMeteredPlan',
|
||||
fixed: 'CreateFixedPlan',
|
||||
}[this.config.subscriptionType]
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config',
|
||||
]),
|
||||
createPlanRoute() {
|
||||
return {
|
||||
metered: 'CreateMeteredPlan',
|
||||
fixed: 'CreateFixedPlan',
|
||||
}[this.config.subscriptionType]
|
||||
},
|
||||
columns() {
|
||||
return {
|
||||
metered: [
|
||||
{
|
||||
label: this.$t('Name'),
|
||||
field: 'name',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('Status'),
|
||||
field: 'status',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('Currency'),
|
||||
field: 'currency',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('Interval'),
|
||||
field: 'interval',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_plans.table.subscribers'),
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
sortable: false
|
||||
},
|
||||
],
|
||||
fixed: [
|
||||
{
|
||||
label: this.$t('Visibility'),
|
||||
field: 'visible',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('Name'),
|
||||
field: 'name',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('Price'),
|
||||
field: 'amount',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('Interval'),
|
||||
field: 'interval',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_plans.table.subscribers'),
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('Storage'),
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
sortable: false
|
||||
},
|
||||
],
|
||||
}[this.config.subscriptionType]
|
||||
}
|
||||
columns() {
|
||||
return {
|
||||
metered: [
|
||||
{
|
||||
label: this.$t('Name'),
|
||||
field: 'name',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('Status'),
|
||||
field: 'status',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('Currency'),
|
||||
field: 'currency',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('Interval'),
|
||||
field: 'interval',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_plans.table.subscribers'),
|
||||
sortable: false,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
sortable: false,
|
||||
},
|
||||
],
|
||||
fixed: [
|
||||
{
|
||||
label: this.$t('Visibility'),
|
||||
field: 'visible',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('Name'),
|
||||
field: 'name',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('Price'),
|
||||
field: 'amount',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('Interval'),
|
||||
field: 'interval',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_plans.table.subscribers'),
|
||||
sortable: false,
|
||||
},
|
||||
{
|
||||
label: this.$t('Storage'),
|
||||
sortable: false,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
sortable: false,
|
||||
},
|
||||
],
|
||||
}[this.config.subscriptionType]
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,197 +1,227 @@
|
||||
<template>
|
||||
<ValidationObserver @submit.prevent="createPlan" ref="createPlan" v-slot="{ invalid }" tag="form">
|
||||
<ValidationObserver @submit.prevent="createPlan" ref="createPlan" v-slot="{ invalid }" tag="form">
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Details') }}
|
||||
</FormLabel>
|
||||
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Details') }}
|
||||
</FormLabel>
|
||||
<!--Name-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Name" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_page_plans.form.name')">
|
||||
<input
|
||||
v-model="plan.name"
|
||||
:placeholder="$t('admin_page_plans.form.name_plac')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<!--Name-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Name" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_page_plans.form.name')">
|
||||
<input v-model="plan.name" :placeholder="$t('admin_page_plans.form.name_plac')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<!--Description-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Description" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_page_plans.form.description')" :is-last="true">
|
||||
<textarea
|
||||
v-model="plan.description"
|
||||
:placeholder="$t('admin_page_plans.form.description_plac')"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
maxlength="120"
|
||||
></textarea>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<!--Description-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Description" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_page_plans.form.description')" :is-last="true">
|
||||
<textarea v-model="plan.description" :placeholder="$t('admin_page_plans.form.description_plac')" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" maxlength="120"></textarea>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Pricing') }}
|
||||
</FormLabel>
|
||||
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Pricing') }}
|
||||
</FormLabel>
|
||||
<div class="justify-items md:flex md:space-x-4">
|
||||
<!--Price-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Price" rules="required" v-slot="{ errors }" class="w-full">
|
||||
<AppInputText :title="$t('admin_page_plans.form.price')" class="w-full">
|
||||
<input
|
||||
v-model="plan.amount"
|
||||
:placeholder="$t('admin_page_plans.form.price_plac')"
|
||||
type="number"
|
||||
step="0.01"
|
||||
min="1"
|
||||
max="999999999999"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<div class="md:flex justify-items md:space-x-4">
|
||||
<!--Price-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Price" rules="required" v-slot="{ errors }" class="w-full">
|
||||
<AppInputText :title="$t('admin_page_plans.form.price')" class="w-full">
|
||||
<input v-model="plan.amount" :placeholder="$t('admin_page_plans.form.price_plac')" type="number" step="0.01" min="1" max="999999999999" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<!--Currency-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Currency" rules="required" v-slot="{ errors }" class="w-full">
|
||||
<AppInputText :title="$t('Currency')" class="w-full">
|
||||
<SelectInput v-model="plan.currency" :options="currencyList" :placeholder="$t('Select plan currency')" :isError="errors[0]" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<!--Currency-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Currency" rules="required" v-slot="{ errors }" class="w-full">
|
||||
<AppInputText :title="$t('Currency')" class="w-full">
|
||||
<SelectInput v-model="plan.currency" :options="currencyList" :placeholder="$t('Select plan currency')" :isError="errors[0]" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<!--Interval-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Interval" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Interval')" :is-last="true">
|
||||
<SelectInput v-model="plan.interval" :options="intervalList" :placeholder="$t('Select billing interval')" :isError="errors[0]" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<!--Interval-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Interval" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Interval')" :is-last="true">
|
||||
<SelectInput v-model="plan.interval" :options="intervalList" :placeholder="$t('Select billing interval')" :isError="errors[0]" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Features') }}
|
||||
</FormLabel>
|
||||
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Features') }}
|
||||
</FormLabel>
|
||||
<!--Storage Capacity-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Max Storage Capacity" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_page_plans.form.storage')" :description="$t('admin_page_plans.form.storage_helper')">
|
||||
<input
|
||||
v-model="plan.features.max_storage_amount"
|
||||
:placeholder="$t('admin_page_plans.form.storage_plac')"
|
||||
type="number"
|
||||
min="1"
|
||||
max="999999999"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<!--Storage Capacity-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Max Storage Capacity" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_page_plans.form.storage')" :description="$t('admin_page_plans.form.storage_helper')">
|
||||
<input v-model="plan.features.max_storage_amount" :placeholder="$t('admin_page_plans.form.storage_plac')" type="number" min="1" max="999999999" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<!--Team Members-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Max Team Members" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Team Members')" :description="$t('To set unlimited team members, type -1 into form')" :is-last="true">
|
||||
<input
|
||||
v-model="plan.features.max_team_members"
|
||||
:placeholder="$t('Add max team members in number')"
|
||||
type="number"
|
||||
min="1"
|
||||
max="999999999"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<!--Team Members-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Max Team Members" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Team Members')" :description="$t('To set unlimited team members, type -1 into form')" :is-last="true">
|
||||
<input v-model="plan.features.max_team_members" :placeholder="$t('Add max team members in number')" type="number" min="1" max="999999999" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<InfoBox v-if="isError" type="error" style="margin-top: 40px">
|
||||
<p>{{ errorMessage }}</p>
|
||||
</InfoBox>
|
||||
|
||||
<InfoBox v-if="isError" type="error" style="margin-top: 40px">
|
||||
<p>{{ errorMessage }}</p>
|
||||
</InfoBox>
|
||||
|
||||
<ButtonBase :disabled="isLoading" :loading="isLoading" button-style="theme" type="submit">
|
||||
{{ $t('admin_page_plans.create_plan_button') }}
|
||||
</ButtonBase>
|
||||
</ValidationObserver>
|
||||
<ButtonBase :disabled="isLoading" :loading="isLoading" button-style="theme" type="submit">
|
||||
{{ $t('admin_page_plans.create_plan_button') }}
|
||||
</ButtonBase>
|
||||
</ValidationObserver>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AppInputText from "../../../../components/Admin/AppInputText";
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import SelectInput from "../../../../components/Others/Forms/SelectInput";
|
||||
import ImageInput from "../../../../components/Others/Forms/ImageInput";
|
||||
import MobileHeader from "../../../../components/Mobile/MobileHeader";
|
||||
import FormLabel from "../../../../components/Others/Forms/FormLabel";
|
||||
import SectionTitle from "../../../../components/Others/SectionTitle";
|
||||
import ButtonBase from "../../../../components/FilesView/ButtonBase";
|
||||
import PageHeader from "../../../../components/Others/PageHeader";
|
||||
import InfoBox from "../../../../components/Others/Forms/InfoBox";
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {mapGetters} from 'vuex'
|
||||
import {events} from '../../../../bus'
|
||||
import axios from 'axios'
|
||||
import AppInputText from '../../../../components/Admin/AppInputText'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import SelectInput from '../../../../components/Others/Forms/SelectInput'
|
||||
import ImageInput from '../../../../components/Others/Forms/ImageInput'
|
||||
import MobileHeader from '../../../../components/Mobile/MobileHeader'
|
||||
import FormLabel from '../../../../components/Others/Forms/FormLabel'
|
||||
import SectionTitle from '../../../../components/Others/SectionTitle'
|
||||
import ButtonBase from '../../../../components/FilesView/ButtonBase'
|
||||
import PageHeader from '../../../../components/Others/PageHeader'
|
||||
import InfoBox from '../../../../components/Others/Forms/InfoBox'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { events } from '../../../../bus'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'CreateFixedPlan',
|
||||
components: {
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SectionTitle,
|
||||
AppInputText,
|
||||
MobileHeader,
|
||||
SelectInput,
|
||||
ButtonBase,
|
||||
ImageInput,
|
||||
PageHeader,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'currencyList',
|
||||
'intervalList',
|
||||
'config',
|
||||
])
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
errorMessage: undefined,
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
plan: {
|
||||
type: 'fixed',
|
||||
name: undefined,
|
||||
description: undefined,
|
||||
interval: undefined,
|
||||
amount: undefined,
|
||||
currency: undefined,
|
||||
features: {
|
||||
max_storage_amount: undefined,
|
||||
max_team_members: undefined,
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async createPlan() {
|
||||
export default {
|
||||
name: 'CreateFixedPlan',
|
||||
components: {
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SectionTitle,
|
||||
AppInputText,
|
||||
MobileHeader,
|
||||
SelectInput,
|
||||
ButtonBase,
|
||||
ImageInput,
|
||||
PageHeader,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['currencyList', 'intervalList', 'config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
errorMessage: undefined,
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
plan: {
|
||||
type: 'fixed',
|
||||
name: undefined,
|
||||
description: undefined,
|
||||
interval: undefined,
|
||||
amount: undefined,
|
||||
currency: undefined,
|
||||
features: {
|
||||
max_storage_amount: undefined,
|
||||
max_team_members: undefined,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async createPlan() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.createPlan.validate()
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.createPlan.validate();
|
||||
if (!isValid) return
|
||||
|
||||
if (!isValid) return;
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
axios
|
||||
.post('/api/subscriptions/admin/plans', this.plan)
|
||||
.then((response) => {
|
||||
// Show toaster
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.plan_created'),
|
||||
})
|
||||
|
||||
axios
|
||||
.post('/api/subscriptions/admin/plans', this.plan)
|
||||
.then(response => {
|
||||
// Go to plan page
|
||||
this.$router.push({
|
||||
name: 'PlanFixedSettings',
|
||||
params: { id: response.data.data.id },
|
||||
})
|
||||
|
||||
// Show toaster
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.plan_created'),
|
||||
})
|
||||
// Set default state {isEmptyPlans} to false
|
||||
if (this.config.isEmptyPlans) {
|
||||
this.$store.commit('REPLACE_CONFIG_VALUE', {
|
||||
key: 'isEmptyPlans',
|
||||
value: false,
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
// Validation errors
|
||||
if (error.response.status === 422) {
|
||||
if (error.response.data.errors['max_storage_amount']) {
|
||||
this.$refs.createPlan.setErrors({
|
||||
'Max Storage Capacity': this.$t('errors.capacity_digit'),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Go to plan page
|
||||
this.$router.push({name: 'PlanFixedSettings', params: {id: response.data.data.id}})
|
||||
|
||||
// Set default state {isEmptyPlans} to false
|
||||
if (this.config.isEmptyPlans) {
|
||||
this.$store.commit('REPLACE_CONFIG_VALUE', {
|
||||
key: 'isEmptyPlans',
|
||||
value: false,
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
// Validation errors
|
||||
if (error.response.status === 422) {
|
||||
|
||||
if (error.response.data.errors['max_storage_amount']) {
|
||||
this.$refs.createPlan.setErrors({
|
||||
'Max Storage Capacity': this.$t('errors.capacity_digit')
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (error.response.status === 500) {
|
||||
this.isError = true
|
||||
this.errorMessage = error.response.data.message
|
||||
}
|
||||
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
if (error.response.status === 500) {
|
||||
this.isError = true
|
||||
this.errorMessage = error.response.data.message
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,243 +1,287 @@
|
||||
<template>
|
||||
<ValidationObserver @submit.prevent="createPlan" ref="createPlan" v-slot="{ invalid }" tag="form">
|
||||
<ValidationObserver @submit.prevent="createPlan" ref="createPlan" v-slot="{ invalid }" tag="form">
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Details') }}
|
||||
</FormLabel>
|
||||
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Details') }}
|
||||
</FormLabel>
|
||||
<!--Name-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Name" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_page_plans.form.name')">
|
||||
<input
|
||||
v-model="plan.name"
|
||||
:placeholder="$t('admin_page_plans.form.name_plac')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<!--Name-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Name" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_page_plans.form.name')">
|
||||
<input v-model="plan.name" :placeholder="$t('admin_page_plans.form.name_plac')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<!--Description-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Description" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_page_plans.form.description')">
|
||||
<textarea
|
||||
v-model="plan.description"
|
||||
:placeholder="$t('admin_page_plans.form.description_plac')"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
></textarea>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<!--Description-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Description" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_page_plans.form.description')">
|
||||
<textarea v-model="plan.description" :placeholder="$t('admin_page_plans.form.description_plac')" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark"></textarea>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<!--Currency-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Currency" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Currency')" class="w-full" :is-last="true">
|
||||
<SelectInput v-model="plan.currency" :options="currencyList" :placeholder="$t('Select plan currency')" :isError="errors[0]" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<!--Currency-->
|
||||
<ValidationProvider tag="div" mode="passive" name="Currency" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Currency')" class="w-full" :is-last="true">
|
||||
<SelectInput v-model="plan.currency" :options="currencyList" :placeholder="$t('Select plan currency')" :isError="errors[0]" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Charged Features') }}
|
||||
</FormLabel>
|
||||
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Charged Features') }}
|
||||
</FormLabel>
|
||||
<!--Bandwidth-->
|
||||
<div>
|
||||
<AppInputSwitch :title="$t('Bandwidth Price per 1GB')" :description="$t('Charge your user by the amount of data he upload or download.')">
|
||||
<SwitchInput v-model="plan.features.bandwidth.active" class="switch" :state="plan.features.bandwidth.active" />
|
||||
</AppInputSwitch>
|
||||
|
||||
<!--Bandwidth-->
|
||||
<div>
|
||||
<AppInputSwitch :title="$t('Bandwidth Price per 1GB')" :description="$t('Charge your user by the amount of data he upload or download.')">
|
||||
<SwitchInput v-model="plan.features.bandwidth.active" class="switch" :state="plan.features.bandwidth.active" />
|
||||
</AppInputSwitch>
|
||||
<ValidationProvider v-if="plan.features.bandwidth.active" class="-mt-3" tag="div" mode="passive" name="Bandwidth Price" rules="required" v-slot="{ errors }">
|
||||
<AppInputText class="w-full">
|
||||
<input
|
||||
v-model="plan.features.bandwidth.per_unit"
|
||||
:placeholder="$t('Type the price per 1GB...')"
|
||||
type="number"
|
||||
step="0.01"
|
||||
min="0.01"
|
||||
max="999999999999"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<ValidationProvider v-if="plan.features.bandwidth.active" class="-mt-3" tag="div" mode="passive" name="Bandwidth Price" rules="required" v-slot="{ errors }">
|
||||
<AppInputText class="w-full">
|
||||
<input v-model="plan.features.bandwidth.per_unit" :placeholder="$t('Type the price per 1GB...')" type="number" step="0.01" min="0.01" max="999999999999" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<!--Storage-->
|
||||
<div>
|
||||
<AppInputSwitch :title="$t('Storage Price per 1GB')" :description="$t('Charge your user by the amount of data he has stored on the disk per 1GB.')">
|
||||
<SwitchInput v-model="plan.features.storage.active" class="switch" :state="plan.features.storage.active" />
|
||||
</AppInputSwitch>
|
||||
</div>
|
||||
|
||||
<!--Storage-->
|
||||
<div>
|
||||
<AppInputSwitch :title="$t('Storage Price per 1GB')" :description="$t('Charge your user by the amount of data he has stored on the disk per 1GB.')">
|
||||
<SwitchInput v-model="plan.features.storage.active" class="switch" :state="plan.features.storage.active" />
|
||||
</AppInputSwitch>
|
||||
</div>
|
||||
<ValidationProvider v-if="plan.features.storage.active" class="-mt-3" tag="div" mode="passive" name="Storage Price" rules="required" v-slot="{ errors }">
|
||||
<AppInputText class="w-full">
|
||||
<input
|
||||
v-model="plan.features.storage.per_unit"
|
||||
:placeholder="$t('Type the price per 1GB...')"
|
||||
type="number"
|
||||
step="0.01"
|
||||
min="0.01"
|
||||
max="999999999999"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<ValidationProvider v-if="plan.features.storage.active" class="-mt-3" tag="div" mode="passive" name="Storage Price" rules="required" v-slot="{ errors }">
|
||||
<AppInputText class="w-full">
|
||||
<input v-model="plan.features.storage.per_unit" :placeholder="$t('Type the price per 1GB...')" type="number" step="0.01" min="0.01" max="999999999999" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<!--Member-->
|
||||
<div>
|
||||
<AppInputSwitch :title="$t('Price per 1 Member')" :description="$t('Charge your user by the total members he use in his Team Folders.')">
|
||||
<SwitchInput v-model="plan.features.member.active" class="switch" :state="plan.features.member.active" />
|
||||
</AppInputSwitch>
|
||||
</div>
|
||||
|
||||
<!--Member-->
|
||||
<div>
|
||||
<AppInputSwitch :title="$t('Price per 1 Member')" :description="$t('Charge your user by the total members he use in his Team Folders.')">
|
||||
<SwitchInput v-model="plan.features.member.active" class="switch" :state="plan.features.member.active" />
|
||||
</AppInputSwitch>
|
||||
</div>
|
||||
<ValidationProvider v-if="plan.features.member.active" class="-mt-3" tag="div" mode="passive" name="Member Price" rules="required" v-slot="{ errors }">
|
||||
<AppInputText class="w-full">
|
||||
<input
|
||||
v-model="plan.features.member.per_unit"
|
||||
:placeholder="$t('Type the price per 1 member...')"
|
||||
type="number"
|
||||
step="0.01"
|
||||
min="0.01"
|
||||
max="999999999999"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<ValidationProvider v-if="plan.features.member.active" class="-mt-3" tag="div" mode="passive" name="Member Price" rules="required" v-slot="{ errors }">
|
||||
<AppInputText class="w-full">
|
||||
<input v-model="plan.features.member.per_unit" :placeholder="$t('Type the price per 1 member...')" type="number" step="0.01" min="0.01" max="999999999999" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<!--Flat Fee-->
|
||||
<div>
|
||||
<AppInputSwitch :title="$t('Flat Fee per Cycle')" :description="$t('Charge monthly flat fee.')" :is-last="!plan.features.flatFee.active">
|
||||
<SwitchInput v-model="plan.features.flatFee.active" class="switch" :state="plan.features.flatFee.active" />
|
||||
</AppInputSwitch>
|
||||
|
||||
<!--Flat Fee-->
|
||||
<div>
|
||||
<AppInputSwitch :title="$t('Flat Fee per Cycle')" :description="$t('Charge monthly flat fee.')" :is-last="! plan.features.flatFee.active">
|
||||
<SwitchInput v-model="plan.features.flatFee.active" class="switch" :state="plan.features.flatFee.active" />
|
||||
</AppInputSwitch>
|
||||
<ValidationProvider v-if="plan.features.flatFee.active" class="-mt-3" tag="div" mode="passive" name="FlatFee Price" rules="required" v-slot="{ errors }">
|
||||
<AppInputText class="w-full" :is-last="true">
|
||||
<input
|
||||
v-model="plan.features.flatFee.per_unit"
|
||||
:placeholder="$t('Type the price...')"
|
||||
type="number"
|
||||
step="0.01"
|
||||
min="0.01"
|
||||
max="999999999999"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ValidationProvider v-if="plan.features.flatFee.active" class="-mt-3" tag="div" mode="passive" name="FlatFee Price" rules="required" v-slot="{ errors }">
|
||||
<AppInputText class="w-full" :is-last="true">
|
||||
<input v-model="plan.features.flatFee.per_unit" :placeholder="$t('Type the price...')" type="number" step="0.01" min="0.01" max="999999999999" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ButtonBase :disabled="isLoading" :loading="isLoading" button-style="theme" type="submit">
|
||||
{{ $t('admin_page_plans.create_plan_button') }}
|
||||
</ButtonBase>
|
||||
</ValidationObserver>
|
||||
<ButtonBase :disabled="isLoading" :loading="isLoading" button-style="theme" type="submit">
|
||||
{{ $t('admin_page_plans.create_plan_button') }}
|
||||
</ButtonBase>
|
||||
</ValidationObserver>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SwitchInput from "../../../../components/Others/Forms/SwitchInput"
|
||||
import AppInputSwitch from "../../../../components/Admin/AppInputSwitch"
|
||||
import AppInputText from "../../../../components/Admin/AppInputText"
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import SelectInput from "../../../../components/Others/Forms/SelectInput";
|
||||
import ImageInput from "../../../../components/Others/Forms/ImageInput";
|
||||
import MobileHeader from "../../../../components/Mobile/MobileHeader";
|
||||
import FormLabel from "../../../../components/Others/Forms/FormLabel";
|
||||
import SectionTitle from "../../../../components/Others/SectionTitle";
|
||||
import ButtonBase from "../../../../components/FilesView/ButtonBase";
|
||||
import PageHeader from "../../../../components/Others/PageHeader";
|
||||
import InfoBox from "../../../../components/Others/Forms/InfoBox";
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {mapGetters} from 'vuex'
|
||||
import {events} from '../../../../bus'
|
||||
import axios from 'axios'
|
||||
import SwitchInput from '../../../../components/Others/Forms/SwitchInput'
|
||||
import AppInputSwitch from '../../../../components/Admin/AppInputSwitch'
|
||||
import AppInputText from '../../../../components/Admin/AppInputText'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import SelectInput from '../../../../components/Others/Forms/SelectInput'
|
||||
import ImageInput from '../../../../components/Others/Forms/ImageInput'
|
||||
import MobileHeader from '../../../../components/Mobile/MobileHeader'
|
||||
import FormLabel from '../../../../components/Others/Forms/FormLabel'
|
||||
import SectionTitle from '../../../../components/Others/SectionTitle'
|
||||
import ButtonBase from '../../../../components/FilesView/ButtonBase'
|
||||
import PageHeader from '../../../../components/Others/PageHeader'
|
||||
import InfoBox from '../../../../components/Others/Forms/InfoBox'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { events } from '../../../../bus'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'CreateMeteredPlan',
|
||||
components: {
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AppInputSwitch,
|
||||
SwitchInput,
|
||||
SectionTitle,
|
||||
AppInputText,
|
||||
MobileHeader,
|
||||
SelectInput,
|
||||
ButtonBase,
|
||||
ImageInput,
|
||||
PageHeader,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'currencyList',
|
||||
'intervalList',
|
||||
])
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
errorMessage: undefined,
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
plan: {
|
||||
type: 'fixed',
|
||||
name: undefined,
|
||||
description: undefined,
|
||||
currency: undefined,
|
||||
features: {
|
||||
bandwidth: {
|
||||
active: false,
|
||||
per_unit: undefined,
|
||||
first_unit: 1,
|
||||
aggregate_strategy: 'sum_of_usage',
|
||||
},
|
||||
storage: {
|
||||
active: false,
|
||||
per_unit: undefined,
|
||||
first_unit: 1,
|
||||
aggregate_strategy: 'maximum_usage',
|
||||
},
|
||||
member: {
|
||||
active: false,
|
||||
per_unit: undefined,
|
||||
first_unit: 1,
|
||||
aggregate_strategy: 'maximum_usage',
|
||||
},
|
||||
flatFee: {
|
||||
active: false,
|
||||
per_unit: undefined,
|
||||
aggregate_strategy: 'maximum_usage',
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async createPlan() {
|
||||
export default {
|
||||
name: 'CreateMeteredPlan',
|
||||
components: {
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AppInputSwitch,
|
||||
SwitchInput,
|
||||
SectionTitle,
|
||||
AppInputText,
|
||||
MobileHeader,
|
||||
SelectInput,
|
||||
ButtonBase,
|
||||
ImageInput,
|
||||
PageHeader,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['currencyList', 'intervalList']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
errorMessage: undefined,
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
plan: {
|
||||
type: 'fixed',
|
||||
name: undefined,
|
||||
description: undefined,
|
||||
currency: undefined,
|
||||
features: {
|
||||
bandwidth: {
|
||||
active: false,
|
||||
per_unit: undefined,
|
||||
first_unit: 1,
|
||||
aggregate_strategy: 'sum_of_usage',
|
||||
},
|
||||
storage: {
|
||||
active: false,
|
||||
per_unit: undefined,
|
||||
first_unit: 1,
|
||||
aggregate_strategy: 'maximum_usage',
|
||||
},
|
||||
member: {
|
||||
active: false,
|
||||
per_unit: undefined,
|
||||
first_unit: 1,
|
||||
aggregate_strategy: 'maximum_usage',
|
||||
},
|
||||
flatFee: {
|
||||
active: false,
|
||||
per_unit: undefined,
|
||||
aggregate_strategy: 'maximum_usage',
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async createPlan() {
|
||||
let tiers = []
|
||||
|
||||
let tiers = []
|
||||
Object.entries(this.plan.features).forEach(([key, feature]) => {
|
||||
if (feature.active) {
|
||||
tiers.push({
|
||||
aggregate_strategy: feature.aggregate_strategy,
|
||||
key: key,
|
||||
tiers: [
|
||||
{
|
||||
per_unit: feature.per_unit,
|
||||
first_unit: 1,
|
||||
flat_fee: null,
|
||||
last_unit: null,
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
Object.entries(this.plan.features).forEach(([key, feature]) => {
|
||||
if (feature.active) {
|
||||
tiers.push({
|
||||
aggregate_strategy: feature.aggregate_strategy,
|
||||
key: key,
|
||||
tiers: [
|
||||
{
|
||||
per_unit: feature.per_unit,
|
||||
first_unit: 1,
|
||||
flat_fee: null,
|
||||
last_unit: null,
|
||||
}
|
||||
]
|
||||
})
|
||||
}
|
||||
})
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.createPlan.validate()
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.createPlan.validate();
|
||||
if (!isValid) return
|
||||
|
||||
if (!isValid) return;
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
axios
|
||||
.post('/api/subscriptions/admin/plans', {
|
||||
type: 'metered',
|
||||
name: this.plan.name,
|
||||
description: this.plan.description,
|
||||
currency: this.plan.currency,
|
||||
meters: tiers,
|
||||
})
|
||||
.then((response) => {
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.plan_created'),
|
||||
})
|
||||
|
||||
axios
|
||||
.post('/api/subscriptions/admin/plans', {
|
||||
type: 'metered',
|
||||
name: this.plan.name,
|
||||
description: this.plan.description,
|
||||
currency: this.plan.currency,
|
||||
meters: tiers
|
||||
})
|
||||
.then(response => {
|
||||
// Go to plan page
|
||||
this.$router.push({
|
||||
name: 'PlanMeteredSettings',
|
||||
params: { id: response.data.data.id },
|
||||
})
|
||||
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.plan_created'),
|
||||
})
|
||||
|
||||
// Go to plan page
|
||||
this.$router.push({name: 'PlanMeteredSettings', params: {id: response.data.data.id}})
|
||||
|
||||
// Set default state {isEmptyPlans} to false
|
||||
if (this.config.isEmptyPlans) {
|
||||
this.$store.commit('REPLACE_CONFIG_VALUE', {
|
||||
key: 'isEmptyPlans',
|
||||
value: false,
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
events.$emit('toaster', {
|
||||
type: 'danger',
|
||||
message: this.$t('popup_error.title'),
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
}
|
||||
// Set default state {isEmptyPlans} to false
|
||||
if (this.config.isEmptyPlans) {
|
||||
this.$store.commit('REPLACE_CONFIG_VALUE', {
|
||||
key: 'isEmptyPlans',
|
||||
value: false,
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
events.$emit('toaster', {
|
||||
type: 'danger',
|
||||
message: this.$t('popup_error.title'),
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="plan" class="card shadow-card sticky top-0 z-10" style="padding-bottom: 0">
|
||||
<div v-if="plan" class="card sticky top-0 z-10 shadow-card" style="padding-bottom: 0">
|
||||
<div class="mb-2">
|
||||
<h1 class="text-lg font-bold sm:text-xl">
|
||||
{{ plan.attributes.name }}
|
||||
</h1>
|
||||
<small class="text-xs font-bold text-gray-500 sm:text-sm">
|
||||
{{ plan.attributes.price }} /
|
||||
{{ $t(`interval.${plan.attributes.interval}`) }}
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<h1 class="font-bold sm:text-xl text-lg">
|
||||
{{ plan.attributes.name }}
|
||||
</h1>
|
||||
<small class="sm:text-sm text-xs font-bold text-gray-500">
|
||||
{{ plan.attributes.price }} / {{ $t(`interval.${plan.attributes.interval}`) }}
|
||||
</small>
|
||||
</div>
|
||||
<CardNavigation :pages="pages" class="-mx-1.5" />
|
||||
</div>
|
||||
|
||||
<CardNavigation :pages="pages" class="-mx-1.5" />
|
||||
</div>
|
||||
|
||||
<router-view v-if="! isLoading" :plan="plan" />
|
||||
<router-view v-if="!isLoading" :plan="plan" />
|
||||
|
||||
<div id="loader" v-if="isLoading">
|
||||
<Spinner></Spinner>
|
||||
@@ -23,44 +23,45 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CardNavigation from "../../../components/Admin/CardNavigation"
|
||||
import Spinner from "../../../components/FilesView/Spinner";
|
||||
import axios from 'axios'
|
||||
import CardNavigation from '../../../components/Admin/CardNavigation'
|
||||
import Spinner from '../../../components/FilesView/Spinner'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'FixedPlan',
|
||||
components: {
|
||||
CardNavigation,
|
||||
Spinner,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
plan: undefined,
|
||||
pages: [
|
||||
{
|
||||
title: this.$t('admin_page_plans.tabs.settings'),
|
||||
route: 'PlanFixedSettings',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_page_plans.tabs.subscribers'),
|
||||
route: 'PlanFixedSubscribers',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_page_plans.tabs.delete'),
|
||||
route: 'PlanFixedDelete',
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
created() {
|
||||
axios.get('/api/subscriptions/admin/plans/' + this.$route.params.id)
|
||||
.then(response => {
|
||||
this.plan = response.data.data
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
export default {
|
||||
name: 'FixedPlan',
|
||||
components: {
|
||||
CardNavigation,
|
||||
Spinner,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
plan: undefined,
|
||||
pages: [
|
||||
{
|
||||
title: this.$t('admin_page_plans.tabs.settings'),
|
||||
route: 'PlanFixedSettings',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_page_plans.tabs.subscribers'),
|
||||
route: 'PlanFixedSubscribers',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_page_plans.tabs.delete'),
|
||||
route: 'PlanFixedDelete',
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
axios
|
||||
.get('/api/subscriptions/admin/plans/' + this.$route.params.id)
|
||||
.then((response) => {
|
||||
this.plan = response.data.data
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="plan" class="card shadow-card sticky top-0 z-10" style="padding-bottom: 0;">
|
||||
<div v-if="plan" class="card sticky top-0 z-10 shadow-card" style="padding-bottom: 0">
|
||||
<div class="mb-2">
|
||||
<h1 class="text-lg font-bold sm:text-xl">
|
||||
{{ plan.attributes.name }}
|
||||
</h1>
|
||||
<small class="text-xs font-bold text-gray-500 sm:text-sm">
|
||||
{{ $t('30 Days intervals') }}
|
||||
</small>
|
||||
</div>
|
||||
|
||||
<div class="mb-2">
|
||||
<h1 class="font-bold sm:text-xl text-lg">
|
||||
{{ plan.attributes.name }}
|
||||
</h1>
|
||||
<small class="sm:text-sm text-xs font-bold text-gray-500">
|
||||
{{ $t('30 Days intervals') }}
|
||||
</small>
|
||||
</div>
|
||||
<!--Navigation-->
|
||||
<CardNavigation :pages="pages" class="-mx-1" />
|
||||
</div>
|
||||
|
||||
<!--Navigation-->
|
||||
<CardNavigation :pages="pages" class="-mx-1" />
|
||||
</div>
|
||||
|
||||
<router-view v-if="! isLoading" :plan="plan" />
|
||||
<router-view v-if="!isLoading" :plan="plan" />
|
||||
|
||||
<div id="loader" v-if="isLoading">
|
||||
<Spinner></Spinner>
|
||||
@@ -24,57 +23,56 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CardNavigation from "../../../components/Admin/CardNavigation"
|
||||
import Spinner from "../../../components/FilesView/Spinner";
|
||||
import axios from 'axios'
|
||||
import {mapGetters} from "vuex";
|
||||
import CardNavigation from '../../../components/Admin/CardNavigation'
|
||||
import Spinner from '../../../components/FilesView/Spinner'
|
||||
import axios from 'axios'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'MeteredPlan',
|
||||
components: {
|
||||
CardNavigation,
|
||||
Spinner,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config'
|
||||
]),
|
||||
pages() {
|
||||
let pages = [
|
||||
{
|
||||
title: this.$t('admin_page_plans.tabs.settings'),
|
||||
route: 'PlanMeteredSettings',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_page_plans.tabs.subscribers'),
|
||||
route: 'PlanMeteredSubscribers',
|
||||
},
|
||||
]
|
||||
export default {
|
||||
name: 'MeteredPlan',
|
||||
components: {
|
||||
CardNavigation,
|
||||
Spinner,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
pages() {
|
||||
let pages = [
|
||||
{
|
||||
title: this.$t('admin_page_plans.tabs.settings'),
|
||||
route: 'PlanMeteredSettings',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_page_plans.tabs.subscribers'),
|
||||
route: 'PlanMeteredSubscribers',
|
||||
},
|
||||
]
|
||||
|
||||
if (this.plan && this.plan.attributes.status === 'active') {
|
||||
pages.push({
|
||||
title: this.$t('admin_page_plans.tabs.delete'),
|
||||
route: 'PlanMeteredDelete',
|
||||
})
|
||||
}
|
||||
if (this.plan && this.plan.attributes.status === 'active') {
|
||||
pages.push({
|
||||
title: this.$t('admin_page_plans.tabs.delete'),
|
||||
route: 'PlanMeteredDelete',
|
||||
})
|
||||
}
|
||||
|
||||
return pages
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
plan: undefined,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
axios.get('/api/subscriptions/admin/plans/' + this.$route.params.id)
|
||||
.then(response => {
|
||||
this.plan = response.data.data
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
return pages
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
plan: undefined,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
axios
|
||||
.get('/api/subscriptions/admin/plans/' + this.$route.params.id)
|
||||
.then((response) => {
|
||||
this.plan = response.data.data
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,86 +1,98 @@
|
||||
<template>
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('admin_page_plans.form.title_delete') }}
|
||||
</FormLabel>
|
||||
<ValidationObserver ref="deletePlan" @submit.prevent="deletePlan" v-slot="{ invalid }" tag="form">
|
||||
<ValidationProvider tag="div" v-slot="{ errors }" mode="passive" name="Plan name" :rules="'required|is:' + plan.attributes.name">
|
||||
<AppInputText :title="$t('admin_page_user.label_delete_user', {user: plan.attributes.name})" :description="$t('admin_page_plans.disclaimer_delete_plan')" :error="errors[0]" :is-last="true">
|
||||
<div class="sm:flex sm:space-x-4 sm:space-y-0 space-y-4">
|
||||
<input v-model="planName" :placeholder="$t('admin_page_plans.form.name_delete_plac')" type="text" :class="{'border-red': errors[0]}" class="focus-border-theme input-dark" />
|
||||
<ButtonBase :loading="isSendingRequest" :disabled="isSendingRequest" type="submit" button-style="danger" class="sm:w-auto w-full">
|
||||
{{ $t('admin_page_plans.delete_plan_button') }}
|
||||
</ButtonBase>
|
||||
</div>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('admin_page_plans.form.title_delete') }}
|
||||
</FormLabel>
|
||||
<ValidationObserver ref="deletePlan" @submit.prevent="deletePlan" v-slot="{ invalid }" tag="form">
|
||||
<ValidationProvider tag="div" v-slot="{ errors }" mode="passive" name="Plan name" :rules="'required|is:' + plan.attributes.name">
|
||||
<AppInputText
|
||||
:title="
|
||||
$t('admin_page_user.label_delete_user', {
|
||||
user: plan.attributes.name,
|
||||
})
|
||||
"
|
||||
:description="$t('admin_page_plans.disclaimer_delete_plan')"
|
||||
:error="errors[0]"
|
||||
:is-last="true"
|
||||
>
|
||||
<div class="space-y-4 sm:flex sm:space-x-4 sm:space-y-0">
|
||||
<input
|
||||
v-model="planName"
|
||||
:placeholder="$t('admin_page_plans.form.name_delete_plac')"
|
||||
type="text"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
<ButtonBase :loading="isSendingRequest" :disabled="isSendingRequest" type="submit" button-style="danger" class="w-full sm:w-auto">
|
||||
{{ $t('admin_page_plans.delete_plan_button') }}
|
||||
</ButtonBase>
|
||||
</div>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AppInputText from "../../../../components/Admin/AppInputText";
|
||||
import FormLabel from "../../../../components/Others/Forms/FormLabel";
|
||||
import InfoBox from "../../../../components/Others/Forms/InfoBox";
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import ButtonBase from "../../../../components/FilesView/ButtonBase";
|
||||
import {required, is} from 'vee-validate/dist/rules'
|
||||
import {events} from '../../../../bus'
|
||||
import axios from 'axios'
|
||||
import AppInputText from '../../../../components/Admin/AppInputText'
|
||||
import FormLabel from '../../../../components/Others/Forms/FormLabel'
|
||||
import InfoBox from '../../../../components/Others/Forms/InfoBox'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import ButtonBase from '../../../../components/FilesView/ButtonBase'
|
||||
import { required, is } from 'vee-validate/dist/rules'
|
||||
import { events } from '../../../../bus'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'PlanDelete',
|
||||
props: [
|
||||
'plan'
|
||||
],
|
||||
components: {
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AppInputText,
|
||||
ButtonBase,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isSendingRequest: false,
|
||||
isLoading: false,
|
||||
planName: '',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async deletePlan() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.deletePlan.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
this.isSendingRequest = true
|
||||
|
||||
axios
|
||||
.post(`/api/subscriptions/admin/plans/${this.$route.params.id}`, {
|
||||
_method: 'delete'
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('popup_deleted_plan.title'),
|
||||
})
|
||||
|
||||
this.$router.push({name: 'Plans'})
|
||||
})
|
||||
.catch(() => {
|
||||
events.$emit('toaster', {
|
||||
type: 'danger',
|
||||
message: this.$t('popup_error.title'),
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
this.isSendingRequest = false
|
||||
})
|
||||
}
|
||||
export default {
|
||||
name: 'PlanDelete',
|
||||
props: ['plan'],
|
||||
components: {
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AppInputText,
|
||||
ButtonBase,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isSendingRequest: false,
|
||||
isLoading: false,
|
||||
planName: '',
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async deletePlan() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.deletePlan.validate()
|
||||
|
||||
if (!isValid) return
|
||||
|
||||
this.isSendingRequest = true
|
||||
|
||||
axios
|
||||
.post(`/api/subscriptions/admin/plans/${this.$route.params.id}`, {
|
||||
_method: 'delete',
|
||||
})
|
||||
.then(() => {
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('popup_deleted_plan.title'),
|
||||
})
|
||||
|
||||
this.$router.push({ name: 'Plans' })
|
||||
})
|
||||
.catch(() => {
|
||||
events.$emit('toaster', {
|
||||
type: 'danger',
|
||||
message: this.$t('popup_error.title'),
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
this.isSendingRequest = false
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,75 +1,107 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Details') }}
|
||||
</FormLabel>
|
||||
<div>
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Details') }}
|
||||
</FormLabel>
|
||||
|
||||
<!--Visible-->
|
||||
<AppInputSwitch :title="$t('admin_page_plans.form.status')" :description="$t('admin_page_plans.form.status_help')">
|
||||
<SwitchInput @input="$updateInput('/subscriptions/admin/plans/' + $route.params.id, 'visible', plan.attributes.visible)" v-model="plan.attributes.visible" class="switch" :state="plan.attributes.visible"/>
|
||||
</AppInputSwitch>
|
||||
<!--Visible-->
|
||||
<AppInputSwitch :title="$t('admin_page_plans.form.status')" :description="$t('admin_page_plans.form.status_help')">
|
||||
<SwitchInput
|
||||
@input="$updateInput('/subscriptions/admin/plans/' + $route.params.id, 'visible', plan.attributes.visible)"
|
||||
v-model="plan.attributes.visible"
|
||||
class="switch"
|
||||
:state="plan.attributes.visible"
|
||||
/>
|
||||
</AppInputSwitch>
|
||||
|
||||
<!--Name-->
|
||||
<AppInputText :title="$t('admin_page_plans.form.name')">
|
||||
<input @input="$updateInput('/subscriptions/admin/plans/' + $route.params.id, 'name', plan.attributes.name)" v-model="plan.attributes.name" :placeholder="$t('admin_page_plans.form.name_plac')" type="text" class="focus-border-theme input-dark"/>
|
||||
</AppInputText>
|
||||
<!--Name-->
|
||||
<AppInputText :title="$t('admin_page_plans.form.name')">
|
||||
<input
|
||||
@input="$updateInput('/subscriptions/admin/plans/' + $route.params.id, 'name', plan.attributes.name)"
|
||||
v-model="plan.attributes.name"
|
||||
:placeholder="$t('admin_page_plans.form.name_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
|
||||
<!--Description-->
|
||||
<AppInputText :title="$t('admin_page_plans.form.description')">
|
||||
<textarea @input="$updateInput('/subscriptions/admin/plans/' + $route.params.id, 'description', plan.attributes.description)" v-model="plan.attributes.description" :placeholder="$t('admin_page_plans.form.description_plac')" class="focus-border-theme input-dark"></textarea>
|
||||
</AppInputText>
|
||||
<!--Description-->
|
||||
<AppInputText :title="$t('admin_page_plans.form.description')">
|
||||
<textarea
|
||||
@input="$updateInput('/subscriptions/admin/plans/' + $route.params.id, 'description', plan.attributes.description)"
|
||||
v-model="plan.attributes.description"
|
||||
:placeholder="$t('admin_page_plans.form.description_plac')"
|
||||
class="focus-border-theme input-dark"
|
||||
></textarea>
|
||||
</AppInputText>
|
||||
|
||||
<InfoBox style="margin-bottom: 0">
|
||||
<p>{{ $t('Price change is not possible. If you would like to change your price or currency, please feel free to create a new plan.') }}</p>
|
||||
</InfoBox>
|
||||
</div>
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Features') }}
|
||||
</FormLabel>
|
||||
<InfoBox style="margin-bottom: 0">
|
||||
<p>
|
||||
{{ $t('Price change is not possible. If you would like to change your price or currency, please feel free to create a new plan.') }}
|
||||
</p>
|
||||
</InfoBox>
|
||||
</div>
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Features') }}
|
||||
</FormLabel>
|
||||
|
||||
<!--Storage Capacity-->
|
||||
<AppInputText :title="$t('admin_page_plans.form.storage')" :description="$t('admin_page_plans.form.storage_helper')">
|
||||
<input @input="$updateInput(`/subscriptions/admin/plans/${$route.params.id}/features`, 'max_storage_amount', plan.attributes.features.max_storage_amount)" v-model="plan.attributes.features.max_storage_amount" :placeholder="$t('admin_page_plans.form.storage_plac')" type="number" min="1" max="999999999" class="focus-border-theme input-dark"/>
|
||||
</AppInputText>
|
||||
<!--Storage Capacity-->
|
||||
<AppInputText :title="$t('admin_page_plans.form.storage')" :description="$t('admin_page_plans.form.storage_helper')">
|
||||
<input
|
||||
@input="$updateInput(`/subscriptions/admin/plans/${$route.params.id}/features`, 'max_storage_amount', plan.attributes.features.max_storage_amount)"
|
||||
v-model="plan.attributes.features.max_storage_amount"
|
||||
:placeholder="$t('admin_page_plans.form.storage_plac')"
|
||||
type="number"
|
||||
min="1"
|
||||
max="999999999"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
|
||||
<!--Team Members-->
|
||||
<AppInputText :title="$t('Max Team Members')" is-last="true">
|
||||
<input @input="$updateInput(`/subscriptions/admin/plans/${$route.params.id}/features`, 'max_team_members', plan.attributes.features.max_team_members)" v-model="plan.attributes.features.max_team_members" :placeholder="$t('Add max team members in number')" type="number" min="1" max="999999999" class="focus-border-theme input-dark"/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
</div>
|
||||
<!--Team Members-->
|
||||
<AppInputText :title="$t('Max Team Members')" is-last="true">
|
||||
<input
|
||||
@input="$updateInput(`/subscriptions/admin/plans/${$route.params.id}/features`, 'max_team_members', plan.attributes.features.max_team_members)"
|
||||
v-model="plan.attributes.features.max_team_members"
|
||||
:placeholder="$t('Add max team members in number')"
|
||||
type="number"
|
||||
min="1"
|
||||
max="999999999"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SwitchInput from "../../../../components/Others/Forms/SwitchInput";
|
||||
import SelectInput from "../../../../components/Others/Forms/SelectInput";
|
||||
import AppInputSwitch from "../../../../components/Admin/AppInputSwitch"
|
||||
import FormLabel from "../../../../components/Others/Forms/FormLabel";
|
||||
import AppInputText from "../../../../components/Admin/AppInputText"
|
||||
import InfoBox from "../../../../components/Others/Forms/InfoBox";
|
||||
import SwitchInput from '../../../../components/Others/Forms/SwitchInput'
|
||||
import SelectInput from '../../../../components/Others/Forms/SelectInput'
|
||||
import AppInputSwitch from '../../../../components/Admin/AppInputSwitch'
|
||||
import FormLabel from '../../../../components/Others/Forms/FormLabel'
|
||||
import AppInputText from '../../../../components/Admin/AppInputText'
|
||||
import InfoBox from '../../../../components/Others/Forms/InfoBox'
|
||||
|
||||
export default {
|
||||
name: 'PlanFixedSettings',
|
||||
props: [
|
||||
'plan'
|
||||
],
|
||||
components: {
|
||||
AppInputSwitch,
|
||||
AppInputText,
|
||||
SwitchInput,
|
||||
SelectInput,
|
||||
FormLabel,
|
||||
InfoBox,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: undefined
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.visible = this.plan.attributes.visible
|
||||
}
|
||||
}
|
||||
export default {
|
||||
name: 'PlanFixedSettings',
|
||||
props: ['plan'],
|
||||
components: {
|
||||
AppInputSwitch,
|
||||
AppInputText,
|
||||
SwitchInput,
|
||||
SelectInput,
|
||||
FormLabel,
|
||||
InfoBox,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: undefined,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.visible = this.plan.attributes.visible
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,91 +1,137 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Details') }}
|
||||
</FormLabel>
|
||||
<div>
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Details') }}
|
||||
</FormLabel>
|
||||
|
||||
<!--Name-->
|
||||
<AppInputText :title="$t('admin_page_plans.form.name')">
|
||||
<input @input="$updateInput('/subscriptions/admin/plans/' + $route.params.id, 'name', plan.attributes.name)" v-model="plan.attributes.name" :placeholder="$t('admin_page_plans.form.name_plac')" type="text" class="focus-border-theme input-dark"/>
|
||||
</AppInputText>
|
||||
<!--Name-->
|
||||
<AppInputText :title="$t('admin_page_plans.form.name')">
|
||||
<input
|
||||
@input="$updateInput('/subscriptions/admin/plans/' + $route.params.id, 'name', plan.attributes.name)"
|
||||
v-model="plan.attributes.name"
|
||||
:placeholder="$t('admin_page_plans.form.name_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
|
||||
<!--Description-->
|
||||
<AppInputText :title="$t('admin_page_plans.form.description')" :is-last="true">
|
||||
<textarea @input="$updateInput('/subscriptions/admin/plans/' + $route.params.id, 'description', plan.attributes.description)" v-model="plan.attributes.description" :placeholder="$t('admin_page_plans.form.description_plac')" class="focus-border-theme input-dark"></textarea>
|
||||
</AppInputText>
|
||||
</div>
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Charged Features') }}
|
||||
</FormLabel>
|
||||
<!--Description-->
|
||||
<AppInputText :title="$t('admin_page_plans.form.description')" :is-last="true">
|
||||
<textarea
|
||||
@input="$updateInput('/subscriptions/admin/plans/' + $route.params.id, 'description', plan.attributes.description)"
|
||||
v-model="plan.attributes.description"
|
||||
:placeholder="$t('admin_page_plans.form.description_plac')"
|
||||
class="focus-border-theme input-dark"
|
||||
></textarea>
|
||||
</AppInputText>
|
||||
</div>
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Charged Features') }}
|
||||
</FormLabel>
|
||||
|
||||
<!--Bandwidth-->
|
||||
<AppInputText v-if="plan.attributes.features.bandwidth" :title="$t('Bandwidth Price per 1GB')" :description="$t('Charge your user by the amount of data he upload or download.')" class="w-full">
|
||||
<input :value="formatCurrency(plan.attributes.currency, plan.attributes.features.bandwidth.tiers[0].per_unit)" type="text" class="focus-border-theme input-dark" disabled/>
|
||||
</AppInputText>
|
||||
<!--Bandwidth-->
|
||||
<AppInputText
|
||||
v-if="plan.attributes.features.bandwidth"
|
||||
:title="$t('Bandwidth Price per 1GB')"
|
||||
:description="$t('Charge your user by the amount of data he upload or download.')"
|
||||
class="w-full"
|
||||
>
|
||||
<input
|
||||
:value="formatCurrency(plan.attributes.currency, plan.attributes.features.bandwidth.tiers[0].per_unit)"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
disabled
|
||||
/>
|
||||
</AppInputText>
|
||||
|
||||
<!--Storage-->
|
||||
<AppInputText v-if="plan.attributes.features.storage" :title="$t('Storage Price per 1GB')" :description="$t('Charge your user by the amount of data he has stored on the disk per 1GB.')" class="w-full">
|
||||
<input :value="formatCurrency(plan.attributes.currency, plan.attributes.features.storage.tiers[0].per_unit)" type="text" class="focus-border-theme input-dark" disabled/>
|
||||
</AppInputText>
|
||||
<!--Storage-->
|
||||
<AppInputText
|
||||
v-if="plan.attributes.features.storage"
|
||||
:title="$t('Storage Price per 1GB')"
|
||||
:description="$t('Charge your user by the amount of data he has stored on the disk per 1GB.')"
|
||||
class="w-full"
|
||||
>
|
||||
<input
|
||||
:value="formatCurrency(plan.attributes.currency, plan.attributes.features.storage.tiers[0].per_unit)"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
disabled
|
||||
/>
|
||||
</AppInputText>
|
||||
|
||||
<!--Member-->
|
||||
<AppInputText v-if="plan.attributes.features.member" :title="$t('Price per 1 Member')" :description="$t('Charge your user by the total members he use in his Team Folders.')" class="w-full">
|
||||
<input :value="formatCurrency(plan.attributes.currency, plan.attributes.features.member.tiers[0].per_unit)" type="text" class="focus-border-theme input-dark" disabled/>
|
||||
</AppInputText>
|
||||
<!--Member-->
|
||||
<AppInputText
|
||||
v-if="plan.attributes.features.member"
|
||||
:title="$t('Price per 1 Member')"
|
||||
:description="$t('Charge your user by the total members he use in his Team Folders.')"
|
||||
class="w-full"
|
||||
>
|
||||
<input
|
||||
:value="formatCurrency(plan.attributes.currency, plan.attributes.features.member.tiers[0].per_unit)"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
disabled
|
||||
/>
|
||||
</AppInputText>
|
||||
|
||||
<!--Flat Fee-->
|
||||
<AppInputText v-if="plan.attributes.features.flatFee" :title="$t('Flat Fee per Cycle')" :description="$t('Charge monthly flat fee.')" class="w-full">
|
||||
<input :value="formatCurrency(plan.attributes.currency, plan.attributes.features.flatFee.tiers[0].per_unit)" type="text" class="focus-border-theme input-dark" disabled/>
|
||||
</AppInputText>
|
||||
<!--Flat Fee-->
|
||||
<AppInputText v-if="plan.attributes.features.flatFee" :title="$t('Flat Fee per Cycle')" :description="$t('Charge monthly flat fee.')" class="w-full">
|
||||
<input
|
||||
:value="formatCurrency(plan.attributes.currency, plan.attributes.features.flatFee.tiers[0].per_unit)"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
disabled
|
||||
/>
|
||||
</AppInputText>
|
||||
|
||||
<InfoBox style="margin-bottom: 0">
|
||||
<p>{{ $t('Price change is not possible. If you would like to change your price or currency, please feel free to create a new plan.') }}</p>
|
||||
</InfoBox>
|
||||
</div>
|
||||
</div>
|
||||
<InfoBox style="margin-bottom: 0">
|
||||
<p>
|
||||
{{ $t('Price change is not possible. If you would like to change your price or currency, please feel free to create a new plan.') }}
|
||||
</p>
|
||||
</InfoBox>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import SwitchInput from "../../../../components/Others/Forms/SwitchInput";
|
||||
import SelectInput from "../../../../components/Others/Forms/SelectInput";
|
||||
import AppInputSwitch from "../../../../components/Admin/AppInputSwitch"
|
||||
import FormLabel from "../../../../components/Others/Forms/FormLabel";
|
||||
import AppInputText from "../../../../components/Admin/AppInputText"
|
||||
import InfoBox from "../../../../components/Others/Forms/InfoBox";
|
||||
import SwitchInput from '../../../../components/Others/Forms/SwitchInput'
|
||||
import SelectInput from '../../../../components/Others/Forms/SelectInput'
|
||||
import AppInputSwitch from '../../../../components/Admin/AppInputSwitch'
|
||||
import FormLabel from '../../../../components/Others/Forms/FormLabel'
|
||||
import AppInputText from '../../../../components/Admin/AppInputText'
|
||||
import InfoBox from '../../../../components/Others/Forms/InfoBox'
|
||||
|
||||
export default {
|
||||
name: 'PlanMeteredSettings',
|
||||
props: [
|
||||
'plan'
|
||||
],
|
||||
components: {
|
||||
AppInputSwitch,
|
||||
AppInputText,
|
||||
SwitchInput,
|
||||
SelectInput,
|
||||
FormLabel,
|
||||
InfoBox,
|
||||
export default {
|
||||
name: 'PlanMeteredSettings',
|
||||
props: ['plan'],
|
||||
components: {
|
||||
AppInputSwitch,
|
||||
AppInputText,
|
||||
SwitchInput,
|
||||
SelectInput,
|
||||
FormLabel,
|
||||
InfoBox,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formatCurrency(currency, amount) {
|
||||
// TODO: add user locale
|
||||
let formatter = new Intl.NumberFormat('en-US', {
|
||||
style: 'currency',
|
||||
currency: currency,
|
||||
})
|
||||
|
||||
return formatter.format(amount)
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
visible: undefined
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
formatCurrency(currency, amount) {
|
||||
// TODO: add user locale
|
||||
let formatter = new Intl.NumberFormat('en-US', {
|
||||
style: 'currency',
|
||||
currency: currency,
|
||||
});
|
||||
|
||||
return formatter.format(amount);
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.visible = this.plan.attributes.visible
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.visible = this.plan.attributes.visible
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,179 +1,191 @@
|
||||
<template>
|
||||
<PageTab :is-loading="isLoading">
|
||||
<DatatableWrapper @data="subscribers = $event" @init="isLoading = false" :api="`/api/subscriptions/admin/plans/${this.$route.params.id}/subscribers`" :paginator="true" :columns="columns" class="card shadow-card overflow-x-auto">
|
||||
<DatatableWrapper
|
||||
@data="subscribers = $event"
|
||||
@init="isLoading = false"
|
||||
:api="`/api/subscriptions/admin/plans/${this.$route.params.id}/subscribers`"
|
||||
:paginator="true"
|
||||
:columns="columns"
|
||||
class="card overflow-x-auto shadow-card"
|
||||
>
|
||||
<!--Table data content-->
|
||||
<template slot-scope="{ row }">
|
||||
<tr v-if="config.subscriptionType === 'metered'" class="whitespace-nowrap border-b border-dashed border-light dark:border-opacity-5">
|
||||
<td class="py-3 pr-3 md:pr-1">
|
||||
<router-link
|
||||
class="flex items-center"
|
||||
:to="{
|
||||
name: 'UserDetail',
|
||||
params: {
|
||||
id: row.data.relationships.user.data.id,
|
||||
},
|
||||
}"
|
||||
>
|
||||
<MemberAvatar :is-border="false" :size="36" :member="row.data.relationships.user" />
|
||||
<div class="ml-3 pr-10">
|
||||
<b class="max-w-1 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold" style="max-width: 155px">
|
||||
{{ row.data.relationships.user.data.attributes.name }}
|
||||
</b>
|
||||
<span class="block text-xs text-gray-600 dark:text-gray-500">
|
||||
{{ row.data.relationships.user.data.attributes.email }}
|
||||
</span>
|
||||
</div>
|
||||
</router-link>
|
||||
</td>
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="whitespace-nowrap text-sm font-bold">
|
||||
{{ row.data.attributes.renews_at }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="pl-3 text-right md:pl-1">
|
||||
<img class="inline-block max-h-5" :src="$getPaymentLogo(row.data.attributes.driver)" :alt="row.data.attributes.driver" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="config.subscriptionType === 'fixed'" class="whitespace-nowrap border-b border-dashed border-light dark:border-opacity-5">
|
||||
<td class="py-3 pr-3 md:pr-1">
|
||||
<router-link
|
||||
class="flex items-center"
|
||||
:to="{
|
||||
name: 'UserDetail',
|
||||
params: {
|
||||
id: row.data.relationships.user.data.id,
|
||||
},
|
||||
}"
|
||||
>
|
||||
<MemberAvatar :is-border="false" :size="36" :member="row.data.relationships.user" />
|
||||
<div class="ml-3 pr-10">
|
||||
<b class="max-w-1 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold" style="max-width: 155px">
|
||||
{{ row.data.relationships.user.data.attributes.name }}
|
||||
</b>
|
||||
<span class="block text-xs text-gray-600 dark:text-gray-500">
|
||||
{{ row.data.relationships.user.data.attributes.email }}
|
||||
</span>
|
||||
</div>
|
||||
</router-link>
|
||||
</td>
|
||||
<td class="px-3 md:px-1">
|
||||
<ColorLabel :color="$getSubscriptionStatusColor(row.data.attributes.status)">
|
||||
{{ row.data.attributes.status }}
|
||||
</ColorLabel>
|
||||
</td>
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="text-limit text-sm font-bold capitalize" style="max-width: 160px">
|
||||
{{ row.data.attributes.name }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="text-sm font-bold">
|
||||
<!--todo: update renew attribute-->
|
||||
{{ row.data.attributes.renews_at ? row.data.attributes.renews_at : row.data.attributes.created_at }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="text-sm font-bold">
|
||||
{{ row.data.attributes.ends_at ? row.data.attributes.ends_at : '-' }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="pl-3 text-right md:pl-1">
|
||||
<img class="inline-block max-h-5" :src="$getPaymentLogo(row.data.attributes.driver)" :alt="row.data.attributes.driver" />
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<!--Table data content-->
|
||||
<template slot-scope="{ row }">
|
||||
<tr v-if="config.subscriptionType === 'metered'" class="border-b dark:border-opacity-5 border-light border-dashed whitespace-nowrap">
|
||||
<td class="py-3 md:pr-1 pr-3">
|
||||
<router-link class="flex items-center" :to="{name: 'UserDetail', params: {id: row.data.relationships.user.data.id}}">
|
||||
<MemberAvatar
|
||||
:is-border="false"
|
||||
:size="36"
|
||||
:member="row.data.relationships.user"
|
||||
/>
|
||||
<div class="ml-3 pr-10">
|
||||
<b class="text-sm font-bold block max-w-1 overflow-hidden text-ellipsis whitespace-nowrap" style="max-width: 155px;">
|
||||
{{ row.data.relationships.user.data.attributes.name }}
|
||||
</b>
|
||||
<span class="block text-xs dark:text-gray-500 text-gray-600">
|
||||
{{ row.data.relationships.user.data.attributes.email }}
|
||||
</span>
|
||||
</div>
|
||||
</router-link>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<span class="text-sm font-bold whitespace-nowrap">
|
||||
{{ row.data.attributes.renews_at }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:pl-1 pl-3 text-right">
|
||||
<img class="inline-block max-h-5" :src="$getPaymentLogo(row.data.attributes.driver)" :alt="row.data.attributes.driver">
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="config.subscriptionType === 'fixed'" class="border-b dark:border-opacity-5 border-light border-dashed whitespace-nowrap">
|
||||
<td class="py-3 md:pr-1 pr-3">
|
||||
<router-link class="flex items-center" :to="{name: 'UserDetail', params: {id: row.data.relationships.user.data.id}}">
|
||||
<MemberAvatar
|
||||
:is-border="false"
|
||||
:size="36"
|
||||
:member="row.data.relationships.user"
|
||||
/>
|
||||
<div class="ml-3 pr-10">
|
||||
<b class="text-sm font-bold block max-w-1 overflow-hidden text-ellipsis whitespace-nowrap" style="max-width: 155px;">
|
||||
{{ row.data.relationships.user.data.attributes.name }}
|
||||
</b>
|
||||
<span class="block text-xs dark:text-gray-500 text-gray-600">
|
||||
{{ row.data.relationships.user.data.attributes.email }}
|
||||
</span>
|
||||
</div>
|
||||
</router-link>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<ColorLabel :color="$getSubscriptionStatusColor(row.data.attributes.status)">
|
||||
{{ row.data.attributes.status }}
|
||||
</ColorLabel>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<span class="text-sm font-bold capitalize text-limit" style="max-width: 160px">
|
||||
{{ row.data.attributes.name }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<span class="text-sm font-bold">
|
||||
<!--todo: update renew attribute-->
|
||||
{{ row.data.attributes.renews_at ? row.data.attributes.renews_at : row.data.attributes.created_at }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<span class="text-sm font-bold">
|
||||
{{ row.data.attributes.ends_at ? row.data.attributes.ends_at : '-' }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:pl-1 pl-3 text-right">
|
||||
<img class="inline-block max-h-5" :src="$getPaymentLogo(row.data.attributes.driver)" :alt="row.data.attributes.driver">
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<!--Empty page-->
|
||||
<template v-slot:empty-page>
|
||||
<InfoBox style="margin-bottom: 0">
|
||||
<p>{{ $t('admin_page_plans.subscribers.empty') }}</p>
|
||||
</InfoBox>
|
||||
</template>
|
||||
</DatatableWrapper>
|
||||
<!--Empty page-->
|
||||
<template v-slot:empty-page>
|
||||
<InfoBox style="margin-bottom: 0">
|
||||
<p>{{ $t('admin_page_plans.subscribers.empty') }}</p>
|
||||
</InfoBox>
|
||||
</template>
|
||||
</DatatableWrapper>
|
||||
</PageTab>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ColorLabel from "../../../../components/Others/ColorLabel";
|
||||
import MemberAvatar from "../../../../components/FilesView/MemberAvatar";
|
||||
import DatatableCellImage from "../../../../components/Others/Tables/DatatableCellImage";
|
||||
import {DownloadCloudIcon, Edit2Icon, Trash2Icon} from "vue-feather-icons"
|
||||
import DatatableWrapper from "../../../../components/Others/Tables/DatatableWrapper";
|
||||
import PageTabGroup from "../../../../components/Others/Layout/PageTabGroup";
|
||||
import PageTab from "../../../../components/Others/Layout/PageTab";
|
||||
import InfoBox from "../../../../components/Others/Forms/InfoBox";
|
||||
import {mapGetters} from "vuex";
|
||||
import ColorLabel from '../../../../components/Others/ColorLabel'
|
||||
import MemberAvatar from '../../../../components/FilesView/MemberAvatar'
|
||||
import DatatableCellImage from '../../../../components/Others/Tables/DatatableCellImage'
|
||||
import { DownloadCloudIcon, Edit2Icon, Trash2Icon } from 'vue-feather-icons'
|
||||
import DatatableWrapper from '../../../../components/Others/Tables/DatatableWrapper'
|
||||
import PageTabGroup from '../../../../components/Others/Layout/PageTabGroup'
|
||||
import PageTab from '../../../../components/Others/Layout/PageTab'
|
||||
import InfoBox from '../../../../components/Others/Forms/InfoBox'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'PlanSubscribers',
|
||||
components: {
|
||||
DatatableCellImage,
|
||||
DownloadCloudIcon,
|
||||
DatatableWrapper,
|
||||
PageTabGroup,
|
||||
MemberAvatar,
|
||||
ColorLabel,
|
||||
Trash2Icon,
|
||||
Edit2Icon,
|
||||
PageTab,
|
||||
InfoBox,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config'
|
||||
]),
|
||||
columns() {
|
||||
return {
|
||||
metered: [
|
||||
{
|
||||
label: this.$t('admin_page_user.table.name'),
|
||||
field: 'user_id',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('Renews At'),
|
||||
field: 'created_at',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('Service'),
|
||||
field: 'driver',
|
||||
sortable: true
|
||||
},
|
||||
],
|
||||
fixed: [
|
||||
{
|
||||
label: this.$t('admin_page_user.table.name'),
|
||||
field: 'user_id',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('Status'),
|
||||
field: 'status',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('Note'),
|
||||
field: 'plan.name',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('Renews At'),
|
||||
field: 'created_at',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('Ends At'),
|
||||
field: 'ends_at',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('Service'),
|
||||
field: 'driver',
|
||||
sortable: true
|
||||
},
|
||||
]
|
||||
}[this.config.subscriptionType]
|
||||
}
|
||||
},
|
||||
data() {
|
||||
export default {
|
||||
name: 'PlanSubscribers',
|
||||
components: {
|
||||
DatatableCellImage,
|
||||
DownloadCloudIcon,
|
||||
DatatableWrapper,
|
||||
PageTabGroup,
|
||||
MemberAvatar,
|
||||
ColorLabel,
|
||||
Trash2Icon,
|
||||
Edit2Icon,
|
||||
PageTab,
|
||||
InfoBox,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
columns() {
|
||||
return {
|
||||
subscribers: undefined,
|
||||
isLoading: true,
|
||||
}
|
||||
metered: [
|
||||
{
|
||||
label: this.$t('admin_page_user.table.name'),
|
||||
field: 'user_id',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('Renews At'),
|
||||
field: 'created_at',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('Service'),
|
||||
field: 'driver',
|
||||
sortable: true,
|
||||
},
|
||||
],
|
||||
fixed: [
|
||||
{
|
||||
label: this.$t('admin_page_user.table.name'),
|
||||
field: 'user_id',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('Status'),
|
||||
field: 'status',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('Note'),
|
||||
field: 'plan.name',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('Renews At'),
|
||||
field: 'created_at',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('Ends At'),
|
||||
field: 'ends_at',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('Service'),
|
||||
field: 'driver',
|
||||
sortable: true,
|
||||
},
|
||||
],
|
||||
}[this.config.subscriptionType]
|
||||
},
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
subscribers: undefined,
|
||||
isLoading: true,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,130 +1,140 @@
|
||||
<template>
|
||||
<div>
|
||||
<!--Datatable-->
|
||||
<DatatableWrapper v-if="! config.isEmptySubscriptions" @init="isLoading = false" api="/api/subscriptions/admin" :paginator="true" :columns="columns" class="card shadow-card overflow-x-auto">
|
||||
<!--Datatable-->
|
||||
<DatatableWrapper
|
||||
v-if="!config.isEmptySubscriptions"
|
||||
@init="isLoading = false"
|
||||
api="/api/subscriptions/admin"
|
||||
:paginator="true"
|
||||
:columns="columns"
|
||||
class="card overflow-x-auto shadow-card"
|
||||
>
|
||||
<!--Table data content-->
|
||||
<template slot-scope="{ row }">
|
||||
<tr class="whitespace-nowrap border-b border-dashed border-light dark:border-opacity-5">
|
||||
<td class="py-5 pr-3 md:pr-1">
|
||||
<router-link
|
||||
class="flex items-center"
|
||||
:to="{
|
||||
name: 'UserDetail',
|
||||
params: {
|
||||
id: row.data.relationships.user.data.id,
|
||||
},
|
||||
}"
|
||||
>
|
||||
<MemberAvatar :is-border="false" :size="36" :member="row.data.relationships.user" />
|
||||
<div class="ml-3 pr-10">
|
||||
<b class="max-w-1 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold" style="max-width: 155px">
|
||||
{{ row.data.relationships.user.data.attributes.name }}
|
||||
</b>
|
||||
<span class="block text-xs text-gray-600 dark:text-gray-500">
|
||||
{{ row.data.relationships.user.data.attributes.email }}
|
||||
</span>
|
||||
</div>
|
||||
</router-link>
|
||||
</td>
|
||||
<td class="px-3 md:px-1">
|
||||
<ColorLabel :color="$getSubscriptionStatusColor(row.data.attributes.status)">
|
||||
{{ row.data.attributes.status }}
|
||||
</ColorLabel>
|
||||
</td>
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="text-limit text-sm font-bold capitalize" style="max-width: 160px">
|
||||
{{ row.data.attributes.name }}
|
||||
</span>
|
||||
<span class="block text-xs font-bold text-gray-400">
|
||||
{{ row.data.relationships.plan.data.attributes.price }}
|
||||
/
|
||||
{{ $t(`interval.${row.data.relationships.plan.data.attributes.interval}`) }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="text-sm font-bold">
|
||||
<!--todo: update renew attribute-->
|
||||
{{ row.data.attributes.renews_at ? row.data.attributes.renews_at : row.data.attributes.created_at }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="text-sm font-bold">
|
||||
{{ row.data.attributes.ends_at ? row.data.attributes.ends_at : '-' }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="pl-3 text-right md:pl-1">
|
||||
<img class="inline-block max-h-5" :src="$getPaymentLogo(row.data.attributes.driver)" :alt="row.data.attributes.driver" />
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</DatatableWrapper>
|
||||
|
||||
<!--Table data content-->
|
||||
<template slot-scope="{ row }">
|
||||
<tr class="border-b dark:border-opacity-5 border-light border-dashed whitespace-nowrap">
|
||||
<td class="py-5 md:pr-1 pr-3">
|
||||
<router-link class="flex items-center" :to="{name: 'UserDetail', params: {id: row.data.relationships.user.data.id}}">
|
||||
<MemberAvatar
|
||||
:is-border="false"
|
||||
:size="36"
|
||||
:member="row.data.relationships.user"
|
||||
/>
|
||||
<div class="ml-3 pr-10">
|
||||
<b class="text-sm font-bold block max-w-1 overflow-hidden text-ellipsis whitespace-nowrap" style="max-width: 155px;">
|
||||
{{ row.data.relationships.user.data.attributes.name }}
|
||||
</b>
|
||||
<span class="block text-xs dark:text-gray-500 text-gray-600">
|
||||
{{ row.data.relationships.user.data.attributes.email }}
|
||||
</span>
|
||||
</div>
|
||||
</router-link>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<ColorLabel :color="$getSubscriptionStatusColor(row.data.attributes.status)">
|
||||
{{ row.data.attributes.status }}
|
||||
</ColorLabel>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<span class="text-sm font-bold capitalize text-limit" style="max-width: 160px">
|
||||
{{ row.data.attributes.name }}
|
||||
</span>
|
||||
<span class="block text-xs font-bold text-gray-400">
|
||||
{{ row.data.relationships.plan.data.attributes.price }} / {{ $t(`interval.${row.data.relationships.plan.data.attributes.interval}`) }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<span class="text-sm font-bold">
|
||||
<!--todo: update renew attribute-->
|
||||
{{ row.data.attributes.renews_at ? row.data.attributes.renews_at : row.data.attributes.created_at }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<span class="text-sm font-bold">
|
||||
{{ row.data.attributes.ends_at ? row.data.attributes.ends_at : '-' }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:pl-1 pl-3 text-right">
|
||||
<img class="inline-block max-h-5" :src="$getPaymentLogo(row.data.attributes.driver)" :alt="row.data.attributes.driver">
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</DatatableWrapper>
|
||||
<!--Empty State-->
|
||||
<div v-if="config.isEmptySubscriptions" class="flex h-full items-center justify-center">
|
||||
<div class="text-center">
|
||||
<img class="mb-6 inline-block w-28" src="https://twemoji.maxcdn.com/v/13.1.0/svg/1f5c3.svg" alt="transaction" />
|
||||
|
||||
<!--Empty State-->
|
||||
<div v-if="config.isEmptySubscriptions" class="flex items-center justify-center h-full">
|
||||
<div class="text-center">
|
||||
<img class="w-28 inline-block mb-6" src="https://twemoji.maxcdn.com/v/13.1.0/svg/1f5c3.svg" alt="transaction">
|
||||
<h1 class="mb-1 text-2xl font-bold">
|
||||
{{ $t('There is Nothing') }}
|
||||
</h1>
|
||||
|
||||
<h1 class="text-2xl font-bold mb-1">
|
||||
{{ $t("There is Nothing") }}
|
||||
</h1>
|
||||
|
||||
<p class="text-sm text-gray-600">
|
||||
{{ $t('All your subscriptions will be visible here') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p class="text-sm text-gray-600">
|
||||
{{ $t('All your subscriptions will be visible here') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ColorLabel from "../../components/Others/ColorLabel";
|
||||
import MemberAvatar from "../../components/FilesView/MemberAvatar";
|
||||
import DatatableWrapper from "../../components/Others/Tables/DatatableWrapper";
|
||||
import { mapGetters } from 'vuex'
|
||||
import ColorLabel from '../../components/Others/ColorLabel'
|
||||
import MemberAvatar from '../../components/FilesView/MemberAvatar'
|
||||
import DatatableWrapper from '../../components/Others/Tables/DatatableWrapper'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Subscriptions',
|
||||
components: {
|
||||
ColorLabel,
|
||||
MemberAvatar,
|
||||
DatatableWrapper,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config',
|
||||
]),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
columns: [
|
||||
{
|
||||
label: this.$t('admin_page_user.table.name'),
|
||||
field: 'user_id',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('Status'),
|
||||
field: 'status',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('Note'),
|
||||
field: 'plan.name',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('Renews At'),
|
||||
field: 'created_at',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('Ends At'),
|
||||
field: 'created_at',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('Service'),
|
||||
field: 'driver.driver',
|
||||
sortable: true
|
||||
},
|
||||
],
|
||||
}
|
||||
export default {
|
||||
name: 'Subscriptions',
|
||||
components: {
|
||||
ColorLabel,
|
||||
MemberAvatar,
|
||||
DatatableWrapper,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
columns: [
|
||||
{
|
||||
label: this.$t('admin_page_user.table.name'),
|
||||
field: 'user_id',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('Status'),
|
||||
field: 'status',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('Note'),
|
||||
field: 'plan.name',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('Renews At'),
|
||||
field: 'created_at',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('Ends At'),
|
||||
field: 'created_at',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('Service'),
|
||||
field: 'driver.driver',
|
||||
sortable: true,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -2,190 +2,221 @@
|
||||
<div>
|
||||
<div class="card shadow-card">
|
||||
<div class="mb-6">
|
||||
<router-link :to="{name: 'UserCreate'}">
|
||||
<router-link :to="{ name: 'UserCreate' }">
|
||||
<MobileActionButton icon="user-plus">
|
||||
{{ $t('admin_page_user.create_user.submit') }}
|
||||
</MobileActionButton>
|
||||
</router-link>
|
||||
|
||||
<MobileActionButton @click.native="$openSpotlight('users')" icon="search">
|
||||
{{ $t('Search') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$openSpotlight('users')" icon="search">
|
||||
{{ $t('Search') }}
|
||||
</MobileActionButton>
|
||||
</div>
|
||||
|
||||
<!--Datatable-->
|
||||
<!--Datatable-->
|
||||
<DatatableWrapper @init="isLoading = false" api="/api/admin/users" :paginator="true" :columns="columns" class="overflow-x-auto">
|
||||
<template slot-scope="{ row }">
|
||||
<!--Not a subscription-->
|
||||
<tr v-if="config.subscriptionType === 'none'" class="border-b dark:border-opacity-5 border-light border-dashed whitespace-nowrap">
|
||||
<td class="py-3 md:pr-1 pr-3">
|
||||
<router-link :to="{name: 'UserDetail', params: {id: row.data.id}}">
|
||||
<div class="flex items-center">
|
||||
<MemberAvatar
|
||||
:is-border="false"
|
||||
:size="44"
|
||||
:member="row.data.relationships.settings"
|
||||
/>
|
||||
<div class="ml-3 pr-10">
|
||||
<b class="text-sm font-bold block max-w-1 overflow-hidden text-ellipsis whitespace-nowrap" style="max-width: 155px;">
|
||||
{{ row.data.relationships.settings.data.attributes.name }}
|
||||
</b>
|
||||
<span class="block text-xs dark:text-gray-500 text-gray-600">
|
||||
{{ row.data.attributes.email }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</router-link>
|
||||
<!--Not a subscription-->
|
||||
<tr v-if="config.subscriptionType === 'none'" class="whitespace-nowrap border-b border-dashed border-light dark:border-opacity-5">
|
||||
<td class="py-3 pr-3 md:pr-1">
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'UserDetail',
|
||||
params: { id: row.data.id },
|
||||
}"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<MemberAvatar :is-border="false" :size="44" :member="row.data.relationships.settings" />
|
||||
<div class="ml-3 pr-10">
|
||||
<b class="max-w-1 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold" style="max-width: 155px">
|
||||
{{ row.data.relationships.settings.data.attributes.name }}
|
||||
</b>
|
||||
<span class="block text-xs text-gray-600 dark:text-gray-500">
|
||||
{{ row.data.attributes.email }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</router-link>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<td class="px-3 md:px-1">
|
||||
<ColorLabel :color="$getUserRoleColor(row.data.attributes.role)">
|
||||
{{ row.data.attributes.role }}
|
||||
</ColorLabel>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<td class="px-3 md:px-1">
|
||||
<span v-if="row.data.attributes.storage.capacity !== 0" class="text-sm font-bold">
|
||||
{{ row.data.attributes.storage.used_formatted }}
|
||||
</span>
|
||||
<span v-if="row.data.attributes.storage.capacity === 0" class="text-sm font-bold">
|
||||
-
|
||||
{{ row.data.attributes.storage.used_formatted }}
|
||||
</span>
|
||||
<span v-if="row.data.attributes.storage.capacity === 0" class="text-sm font-bold"> - </span>
|
||||
</td>
|
||||
<td class="md:px-1 px-3" v-if="config.storageLimit">
|
||||
<td class="px-3 md:px-1" v-if="config.storageLimit">
|
||||
<span v-if="row.data.attributes.storage.capacity !== 0" class="text-sm font-bold">
|
||||
{{ row.data.attributes.storage.capacity_formatted }}
|
||||
</span>
|
||||
<span v-if="row.data.attributes.storage.capacity === 0" class="text-sm font-bold">
|
||||
-
|
||||
{{ row.data.attributes.storage.capacity_formatted }}
|
||||
</span>
|
||||
<span v-if="row.data.attributes.storage.capacity === 0" class="text-sm font-bold"> - </span>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="text-sm font-bold">
|
||||
{{ row.data.attributes.created_at }}
|
||||
{{ row.data.attributes.created_at }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:pl-1 pl-3 text-right">
|
||||
<div class="flex space-x-2 w-full justify-end">
|
||||
<router-link class="flex items-center justify-center w-8 h-8 rounded-md hover:bg-green-100 dark:bg-2x-dark-foreground bg-light-background transition-colors" :to="{name: 'UserDetail', params: {id: row.data.id}}">
|
||||
<td class="pl-3 text-right md:pl-1">
|
||||
<div class="flex w-full justify-end space-x-2">
|
||||
<router-link
|
||||
class="flex h-8 w-8 items-center justify-center rounded-md bg-light-background transition-colors hover:bg-green-100 dark:bg-2x-dark-foreground"
|
||||
:to="{
|
||||
name: 'UserDetail',
|
||||
params: { id: row.data.id },
|
||||
}"
|
||||
>
|
||||
<Edit2Icon size="15" class="opacity-75" />
|
||||
</router-link>
|
||||
<router-link class="flex items-center justify-center w-8 h-8 rounded-md hover:bg-red-100 dark:bg-2x-dark-foreground bg-light-background transition-colors" :to="{name: 'UserDelete', params: {id: row.data.id}}">
|
||||
<router-link
|
||||
class="flex h-8 w-8 items-center justify-center rounded-md bg-light-background transition-colors hover:bg-red-100 dark:bg-2x-dark-foreground"
|
||||
:to="{
|
||||
name: 'UserDelete',
|
||||
params: { id: row.data.id },
|
||||
}"
|
||||
>
|
||||
<Trash2Icon size="15" class="opacity-75" />
|
||||
</router-link>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!--Fixed subscription-->
|
||||
<tr v-if="config.subscriptionType === 'fixed'" class="border-b dark:border-opacity-5 border-light border-dashed whitespace-nowrap">
|
||||
<td class="py-3 md:pr-1 pr-3">
|
||||
<router-link :to="{name: 'UserDetail', params: {id: row.data.id}}">
|
||||
<div class="flex items-center">
|
||||
<MemberAvatar
|
||||
:is-border="false"
|
||||
:size="44"
|
||||
:member="row.data.relationships.settings"
|
||||
/>
|
||||
<div class="ml-3 pr-10">
|
||||
<b class="text-sm font-bold block max-w-1 overflow-hidden text-ellipsis whitespace-nowrap" style="max-width: 155px;">
|
||||
{{ row.data.relationships.settings.data.attributes.name }}
|
||||
</b>
|
||||
<span class="block text-xs dark:text-gray-500 text-gray-600">
|
||||
{{ row.data.attributes.email }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</router-link>
|
||||
<!--Fixed subscription-->
|
||||
<tr v-if="config.subscriptionType === 'fixed'" class="whitespace-nowrap border-b border-dashed border-light dark:border-opacity-5">
|
||||
<td class="py-3 pr-3 md:pr-1">
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'UserDetail',
|
||||
params: { id: row.data.id },
|
||||
}"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<MemberAvatar :is-border="false" :size="44" :member="row.data.relationships.settings" />
|
||||
<div class="ml-3 pr-10">
|
||||
<b class="max-w-1 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold" style="max-width: 155px">
|
||||
{{ row.data.relationships.settings.data.attributes.name }}
|
||||
</b>
|
||||
<span class="block text-xs text-gray-600 dark:text-gray-500">
|
||||
{{ row.data.attributes.email }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</router-link>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<td class="px-3 md:px-1">
|
||||
<ColorLabel :color="$getUserRoleColor(row.data.attributes.role)">
|
||||
{{ row.data.attributes.role }}
|
||||
</ColorLabel>
|
||||
</td>
|
||||
<td class="md:px-1 px-3" v-if="config.isSaaS">
|
||||
<td class="px-3 md:px-1" v-if="config.isSaaS">
|
||||
<span class="text-sm font-bold">
|
||||
{{ row.data.relationships.subscription ? $t('global.premium') : $t('global.free') }}
|
||||
{{ row.data.relationships.subscription ? $t('global.premium') : $t('global.free') }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<td class="px-3 md:px-1">
|
||||
<span v-if="row.data.attributes.storage.capacity !== 0" class="text-sm font-bold">
|
||||
{{ row.data.attributes.storage.used_formatted }}
|
||||
</span>
|
||||
<span v-if="row.data.attributes.storage.capacity === 0" class="text-sm font-bold">
|
||||
-
|
||||
{{ row.data.attributes.storage.used_formatted }}
|
||||
</span>
|
||||
<span v-if="row.data.attributes.storage.capacity === 0" class="text-sm font-bold"> - </span>
|
||||
</td>
|
||||
<td class="md:px-1 px-3" v-if="config.storageLimit">
|
||||
<td class="px-3 md:px-1" v-if="config.storageLimit">
|
||||
<span v-if="row.data.attributes.storage.capacity !== 0" class="text-sm font-bold">
|
||||
{{ row.data.attributes.storage.capacity_formatted }}
|
||||
</span>
|
||||
<span v-if="row.data.attributes.storage.capacity === 0" class="text-sm font-bold">
|
||||
-
|
||||
{{ row.data.attributes.storage.capacity_formatted }}
|
||||
</span>
|
||||
<span v-if="row.data.attributes.storage.capacity === 0" class="text-sm font-bold"> - </span>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="text-sm font-bold">
|
||||
{{ row.data.attributes.created_at }}
|
||||
{{ row.data.attributes.created_at }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:pl-1 pl-3 text-right">
|
||||
<div class="flex space-x-2 w-full justify-end">
|
||||
<router-link class="flex items-center justify-center w-8 h-8 rounded-md hover:bg-green-100 dark:bg-2x-dark-foreground bg-light-background transition-colors" :to="{name: 'UserDetail', params: {id: row.data.id}}">
|
||||
<td class="pl-3 text-right md:pl-1">
|
||||
<div class="flex w-full justify-end space-x-2">
|
||||
<router-link
|
||||
class="flex h-8 w-8 items-center justify-center rounded-md bg-light-background transition-colors hover:bg-green-100 dark:bg-2x-dark-foreground"
|
||||
:to="{
|
||||
name: 'UserDetail',
|
||||
params: { id: row.data.id },
|
||||
}"
|
||||
>
|
||||
<Edit2Icon size="15" class="opacity-75" />
|
||||
</router-link>
|
||||
<router-link class="flex items-center justify-center w-8 h-8 rounded-md hover:bg-red-100 dark:bg-2x-dark-foreground bg-light-background transition-colors" :to="{name: 'UserDelete', params: {id: row.data.id}}">
|
||||
<router-link
|
||||
class="flex h-8 w-8 items-center justify-center rounded-md bg-light-background transition-colors hover:bg-red-100 dark:bg-2x-dark-foreground"
|
||||
:to="{
|
||||
name: 'UserDelete',
|
||||
params: { id: row.data.id },
|
||||
}"
|
||||
>
|
||||
<Trash2Icon size="15" class="opacity-75" />
|
||||
</router-link>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!--Metered subscription-->
|
||||
<tr v-if="config.subscriptionType === 'metered'" class="border-b dark:border-opacity-5 border-light border-dashed whitespace-nowrap">
|
||||
<td class="py-3 md:pr-1 pr-3">
|
||||
<router-link :to="{name: 'UserDetail', params: {id: row.data.id}}">
|
||||
<div class="flex items-center">
|
||||
<MemberAvatar
|
||||
:is-border="false"
|
||||
:size="44"
|
||||
:member="row.data.relationships.settings"
|
||||
/>
|
||||
<div class="ml-3 pr-10">
|
||||
<b class="text-sm font-bold block max-w-1 overflow-hidden text-ellipsis whitespace-nowrap" style="max-width: 155px;">
|
||||
{{ row.data.relationships.settings.data.attributes.name }}
|
||||
</b>
|
||||
<span class="block text-xs dark:text-gray-500 text-gray-600">
|
||||
{{ row.data.attributes.email }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</router-link>
|
||||
<!--Metered subscription-->
|
||||
<tr v-if="config.subscriptionType === 'metered'" class="whitespace-nowrap border-b border-dashed border-light dark:border-opacity-5">
|
||||
<td class="py-3 pr-3 md:pr-1">
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'UserDetail',
|
||||
params: { id: row.data.id },
|
||||
}"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<MemberAvatar :is-border="false" :size="44" :member="row.data.relationships.settings" />
|
||||
<div class="ml-3 pr-10">
|
||||
<b class="max-w-1 block overflow-hidden text-ellipsis whitespace-nowrap text-sm font-bold" style="max-width: 155px">
|
||||
{{ row.data.relationships.settings.data.attributes.name }}
|
||||
</b>
|
||||
<span class="block text-xs text-gray-600 dark:text-gray-500">
|
||||
{{ row.data.attributes.email }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</router-link>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<td class="px-3 md:px-1">
|
||||
<ColorLabel :color="$getUserRoleColor(row.data.attributes.role)">
|
||||
{{ row.data.attributes.role }}
|
||||
</ColorLabel>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="text-sm font-bold">
|
||||
{{ row.data.meta.usages.featureEstimates.storage.usage }}
|
||||
{{ row.data.meta.usages.featureEstimates.storage.usage }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="text-sm font-bold">
|
||||
{{ row.data.meta.usages.costEstimate }}
|
||||
{{ row.data.meta.usages.costEstimate }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:px-1 px-3">
|
||||
<td class="px-3 md:px-1">
|
||||
<span class="text-sm font-bold">
|
||||
{{ row.data.attributes.created_at }}
|
||||
{{ row.data.attributes.created_at }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="md:pl-1 pl-3 text-right">
|
||||
<div class="flex space-x-2 w-full justify-end">
|
||||
<router-link class="flex items-center justify-center w-8 h-8 rounded-md hover:bg-green-100 dark:bg-2x-dark-foreground bg-light-background transition-colors" :to="{name: 'UserDetail', params: {id: row.data.id}}">
|
||||
<td class="pl-3 text-right md:pl-1">
|
||||
<div class="flex w-full justify-end space-x-2">
|
||||
<router-link
|
||||
class="flex h-8 w-8 items-center justify-center rounded-md bg-light-background transition-colors hover:bg-green-100 dark:bg-2x-dark-foreground"
|
||||
:to="{
|
||||
name: 'UserDetail',
|
||||
params: { id: row.data.id },
|
||||
}"
|
||||
>
|
||||
<Edit2Icon size="15" class="opacity-75" />
|
||||
</router-link>
|
||||
<router-link class="flex items-center justify-center w-8 h-8 rounded-md hover:bg-red-100 dark:bg-2x-dark-foreground bg-light-background transition-colors" :to="{name: 'UserDelete', params: {id: row.data.id}}">
|
||||
<router-link
|
||||
class="flex h-8 w-8 items-center justify-center rounded-md bg-light-background transition-colors hover:bg-red-100 dark:bg-2x-dark-foreground"
|
||||
:to="{
|
||||
name: 'UserDelete',
|
||||
params: { id: row.data.id },
|
||||
}"
|
||||
>
|
||||
<Trash2Icon size="15" class="opacity-75" />
|
||||
</router-link>
|
||||
</div>
|
||||
@@ -201,142 +232,140 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MemberAvatar from "../../components/FilesView/MemberAvatar";
|
||||
import DatatableCellImage from "../../components/Others/Tables/DatatableCellImage";
|
||||
import DatatableWrapper from "../../components/Others/Tables/DatatableWrapper";
|
||||
import MobileActionButton from "../../components/FilesView/MobileActionButton";
|
||||
import MobileHeader from "../../components/Mobile/MobileHeader";
|
||||
import SectionTitle from "../../components/Others/SectionTitle";
|
||||
import ButtonBase from "../../components/FilesView/ButtonBase";
|
||||
import PageHeader from "../../components/Others/PageHeader";
|
||||
import ColorLabel from "../../components/Others/ColorLabel";
|
||||
import Spinner from "../../components/FilesView/Spinner";
|
||||
import {Trash2Icon, Edit2Icon} from "vue-feather-icons";
|
||||
import {mapGetters} from "vuex"
|
||||
import axios from 'axios'
|
||||
import MemberAvatar from '../../components/FilesView/MemberAvatar'
|
||||
import DatatableCellImage from '../../components/Others/Tables/DatatableCellImage'
|
||||
import DatatableWrapper from '../../components/Others/Tables/DatatableWrapper'
|
||||
import MobileActionButton from '../../components/FilesView/MobileActionButton'
|
||||
import MobileHeader from '../../components/Mobile/MobileHeader'
|
||||
import SectionTitle from '../../components/Others/SectionTitle'
|
||||
import ButtonBase from '../../components/FilesView/ButtonBase'
|
||||
import PageHeader from '../../components/Others/PageHeader'
|
||||
import ColorLabel from '../../components/Others/ColorLabel'
|
||||
import Spinner from '../../components/FilesView/Spinner'
|
||||
import { Trash2Icon, Edit2Icon } from 'vue-feather-icons'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'Users',
|
||||
components: {
|
||||
DatatableCellImage,
|
||||
MobileActionButton,
|
||||
DatatableWrapper,
|
||||
MemberAvatar,
|
||||
SectionTitle,
|
||||
MobileHeader,
|
||||
Trash2Icon,
|
||||
PageHeader,
|
||||
ButtonBase,
|
||||
ColorLabel,
|
||||
Edit2Icon,
|
||||
Spinner,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config'
|
||||
]),
|
||||
columns() {
|
||||
return {
|
||||
metered: [
|
||||
{
|
||||
label: this.$t('admin_page_user.table.name'),
|
||||
field: 'email',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.role'),
|
||||
field: 'role',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.storage_used'),
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('Billing Est.'),
|
||||
sortable: false,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.created_at'),
|
||||
field: 'created_at',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
sortable: false
|
||||
},
|
||||
],
|
||||
fixed: [
|
||||
{
|
||||
label: this.$t('admin_page_user.table.name'),
|
||||
field: 'email',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.role'),
|
||||
field: 'role',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.plan'),
|
||||
sortable: false,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.storage_used'),
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('Max Storage'),
|
||||
sortable: false,
|
||||
hidden: ! this.config.storageLimit,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.created_at'),
|
||||
field: 'created_at',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
sortable: false
|
||||
},
|
||||
],
|
||||
none: [
|
||||
{
|
||||
label: this.$t('admin_page_user.table.name'),
|
||||
field: 'email',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.role'),
|
||||
field: 'role',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.storage_used'),
|
||||
sortable: false
|
||||
},
|
||||
{
|
||||
label: this.$t('Max Storage'),
|
||||
sortable: false,
|
||||
hidden: ! this.config.storageLimit,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.created_at'),
|
||||
field: 'created_at',
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
sortable: false
|
||||
},
|
||||
],
|
||||
}[this.config.subscriptionType]
|
||||
}
|
||||
},
|
||||
data() {
|
||||
export default {
|
||||
name: 'Users',
|
||||
components: {
|
||||
DatatableCellImage,
|
||||
MobileActionButton,
|
||||
DatatableWrapper,
|
||||
MemberAvatar,
|
||||
SectionTitle,
|
||||
MobileHeader,
|
||||
Trash2Icon,
|
||||
PageHeader,
|
||||
ButtonBase,
|
||||
ColorLabel,
|
||||
Edit2Icon,
|
||||
Spinner,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
columns() {
|
||||
return {
|
||||
isLoading: true,
|
||||
}
|
||||
metered: [
|
||||
{
|
||||
label: this.$t('admin_page_user.table.name'),
|
||||
field: 'email',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.role'),
|
||||
field: 'role',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.storage_used'),
|
||||
sortable: false,
|
||||
},
|
||||
{
|
||||
label: this.$t('Billing Est.'),
|
||||
sortable: false,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.created_at'),
|
||||
field: 'created_at',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
sortable: false,
|
||||
},
|
||||
],
|
||||
fixed: [
|
||||
{
|
||||
label: this.$t('admin_page_user.table.name'),
|
||||
field: 'email',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.role'),
|
||||
field: 'role',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.plan'),
|
||||
sortable: false,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.storage_used'),
|
||||
sortable: false,
|
||||
},
|
||||
{
|
||||
label: this.$t('Max Storage'),
|
||||
sortable: false,
|
||||
hidden: !this.config.storageLimit,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.created_at'),
|
||||
field: 'created_at',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
sortable: false,
|
||||
},
|
||||
],
|
||||
none: [
|
||||
{
|
||||
label: this.$t('admin_page_user.table.name'),
|
||||
field: 'email',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.role'),
|
||||
field: 'role',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.storage_used'),
|
||||
sortable: false,
|
||||
},
|
||||
{
|
||||
label: this.$t('Max Storage'),
|
||||
sortable: false,
|
||||
hidden: !this.config.storageLimit,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.created_at'),
|
||||
field: 'created_at',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
label: this.$t('admin_page_user.table.action'),
|
||||
sortable: false,
|
||||
},
|
||||
],
|
||||
}[this.config.subscriptionType]
|
||||
},
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,39 +1,38 @@
|
||||
<template>
|
||||
<div>
|
||||
<div id="page-content" v-if="! isLoading">
|
||||
<!--Page Tab links-->
|
||||
<div class="card shadow-card pt-4 sticky top-0 z-10" style="padding-bottom: 0;">
|
||||
<div id="page-content" v-if="!isLoading">
|
||||
<!--Page Tab links-->
|
||||
<div class="card sticky top-0 z-10 pt-4 shadow-card" style="padding-bottom: 0">
|
||||
<!--User thumbnail-->
|
||||
<div class="mb-3 flex items-center">
|
||||
<!--Image input for replace avatar-->
|
||||
<img
|
||||
:src="user.data.relationships.settings.data.attributes.avatar.sm"
|
||||
:alt="user.data.relationships.settings.data.attributes.name"
|
||||
class="relative z-0 h-14 w-14 cursor-pointer rounded-xl object-cover shadow-lg md:h-16 md:w-16"
|
||||
/>
|
||||
|
||||
<!--User name & email-->
|
||||
<div class="ml-4">
|
||||
<b class="text-md block font-bold sm:text-lg">
|
||||
{{ user.data.relationships.settings.data.attributes.first_name }}
|
||||
{{ user.data.relationships.settings.data.attributes.last_name }}
|
||||
|
||||
<!--User thumbnail-->
|
||||
<div class="flex items-center mb-3">
|
||||
<ColorLabel color="purple">
|
||||
{{ user.data.attributes.role }}
|
||||
</ColorLabel>
|
||||
</b>
|
||||
<small class="block text-xs text-gray-600 sm:text-sm">
|
||||
{{ user.data.attributes.email }}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Image input for replace avatar-->
|
||||
<img
|
||||
:src="user.data.relationships.settings.data.attributes.avatar.sm" :alt="user.data.relationships.settings.data.attributes.name"
|
||||
class="md:w-16 w-14 md:h-16 h-14 object-cover rounded-xl relative z-0 shadow-lg cursor-pointer"
|
||||
/>
|
||||
<CardNavigation :pages="pages" class="-mx-1" />
|
||||
</div>
|
||||
|
||||
<!--User name & email-->
|
||||
<div class="ml-4">
|
||||
<b class="sm:text-lg text-md font-bold block">
|
||||
{{ user.data.relationships.settings.data.attributes.first_name }} {{ user.data.relationships.settings.data.attributes.last_name }}
|
||||
|
||||
<ColorLabel color="purple">
|
||||
{{ user.data.attributes.role }}
|
||||
</ColorLabel>
|
||||
</b>
|
||||
<small class="sm:text-sm text-xs text-gray-600 block">
|
||||
{{ user.data.attributes.email }}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<CardNavigation :pages="pages" class="-mx-1" />
|
||||
</div>
|
||||
|
||||
<!--Router Content-->
|
||||
<router-view :user="user" @reload-user="fetchUser"/>
|
||||
<!--Router Content-->
|
||||
<router-view :user="user" @reload-user="fetchUser" />
|
||||
</div>
|
||||
<div id="loader" v-if="isLoading">
|
||||
<Spinner />
|
||||
@@ -42,110 +41,107 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CardNavigation from "../../../components/Admin/CardNavigation";
|
||||
import {UserIcon, HardDriveIcon, LockIcon, Trash2Icon, FileTextIcon, CreditCardIcon} from 'vue-feather-icons'
|
||||
import MobileHeader from "../../../components/Mobile/MobileHeader";
|
||||
import SectionTitle from "../../../components/Others/SectionTitle";
|
||||
import PageHeader from "../../../components/Others/PageHeader";
|
||||
import ColorLabel from "../../../components/Others/ColorLabel";
|
||||
import Spinner from "../../../components/FilesView/Spinner";
|
||||
import {events} from '../../../bus'
|
||||
import {mapGetters} from 'vuex'
|
||||
import axios from 'axios'
|
||||
import CardNavigation from '../../../components/Admin/CardNavigation'
|
||||
import { UserIcon, HardDriveIcon, LockIcon, Trash2Icon, FileTextIcon, CreditCardIcon } from 'vue-feather-icons'
|
||||
import MobileHeader from '../../../components/Mobile/MobileHeader'
|
||||
import SectionTitle from '../../../components/Others/SectionTitle'
|
||||
import PageHeader from '../../../components/Others/PageHeader'
|
||||
import ColorLabel from '../../../components/Others/ColorLabel'
|
||||
import Spinner from '../../../components/FilesView/Spinner'
|
||||
import { events } from '../../../bus'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'Profile',
|
||||
components: {
|
||||
CardNavigation,
|
||||
CreditCardIcon,
|
||||
HardDriveIcon,
|
||||
SectionTitle,
|
||||
FileTextIcon,
|
||||
MobileHeader,
|
||||
PageHeader,
|
||||
ColorLabel,
|
||||
Trash2Icon,
|
||||
UserIcon,
|
||||
LockIcon,
|
||||
Spinner,
|
||||
},
|
||||
watch: {
|
||||
'$route.fullPath': function() {
|
||||
this.fetchUser()
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config'
|
||||
]),
|
||||
admin() {
|
||||
return this.$store.getters.user ? this.$store.getters.user : undefined
|
||||
},
|
||||
pages() {
|
||||
if (this.config.subscriptionType === 'none') {
|
||||
return [
|
||||
{
|
||||
title: this.$t('admin_page_user.tabs.detail'),
|
||||
route: 'UserDetail',
|
||||
},
|
||||
{
|
||||
title: this.$t('Storage'),
|
||||
route: 'UserStorage',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_page_user.tabs.password'),
|
||||
route: 'UserPassword',
|
||||
},
|
||||
{
|
||||
title: this.$t('Delete Account'),
|
||||
route: 'UserDelete',
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
title: this.$t('admin_page_user.tabs.detail'),
|
||||
route: 'UserDetail',
|
||||
},
|
||||
{
|
||||
title: this.$t('Storage'),
|
||||
route: 'UserStorage',
|
||||
},
|
||||
{
|
||||
title: this.$t('Billing'),
|
||||
route: 'UserSubscription',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_page_user.tabs.password'),
|
||||
route: 'UserPassword',
|
||||
},
|
||||
{
|
||||
title: this.$t('Delete Account'),
|
||||
route: 'UserDelete',
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
user: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fetchUser() {
|
||||
axios.get('/api/admin/users/' + this.$route.params.id)
|
||||
.then(response => {
|
||||
this.user = response.data
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
export default {
|
||||
name: 'Profile',
|
||||
components: {
|
||||
CardNavigation,
|
||||
CreditCardIcon,
|
||||
HardDriveIcon,
|
||||
SectionTitle,
|
||||
FileTextIcon,
|
||||
MobileHeader,
|
||||
PageHeader,
|
||||
ColorLabel,
|
||||
Trash2Icon,
|
||||
UserIcon,
|
||||
LockIcon,
|
||||
Spinner,
|
||||
},
|
||||
watch: {
|
||||
'$route.fullPath': function () {
|
||||
this.fetchUser()
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
admin() {
|
||||
return this.$store.getters.user ? this.$store.getters.user : undefined
|
||||
},
|
||||
pages() {
|
||||
if (this.config.subscriptionType === 'none') {
|
||||
return [
|
||||
{
|
||||
title: this.$t('admin_page_user.tabs.detail'),
|
||||
route: 'UserDetail',
|
||||
},
|
||||
{
|
||||
title: this.$t('Storage'),
|
||||
route: 'UserStorage',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_page_user.tabs.password'),
|
||||
route: 'UserPassword',
|
||||
},
|
||||
{
|
||||
title: this.$t('Delete Account'),
|
||||
route: 'UserDelete',
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
events.$on('reload:user', () => this.fetchUser())
|
||||
return [
|
||||
{
|
||||
title: this.$t('admin_page_user.tabs.detail'),
|
||||
route: 'UserDetail',
|
||||
},
|
||||
{
|
||||
title: this.$t('Storage'),
|
||||
route: 'UserStorage',
|
||||
},
|
||||
{
|
||||
title: this.$t('Billing'),
|
||||
route: 'UserSubscription',
|
||||
},
|
||||
{
|
||||
title: this.$t('admin_page_user.tabs.password'),
|
||||
route: 'UserPassword',
|
||||
},
|
||||
{
|
||||
title: this.$t('Delete Account'),
|
||||
route: 'UserDelete',
|
||||
},
|
||||
]
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
user: undefined,
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
fetchUser() {
|
||||
axios.get('/api/admin/users/' + this.$route.params.id).then((response) => {
|
||||
this.user = response.data
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.fetchUser()
|
||||
|
||||
events.$on('reload:user', () => this.fetchUser())
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -3,37 +3,61 @@
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>{{ $t('admin_page_user.create_user.group_details') }}</FormLabel>
|
||||
|
||||
<!--Avatar-->
|
||||
<ValidationProvider tag="div" mode="passive" name="avatar" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_page_user.create_user.avatar')" :error="errors[0]">
|
||||
<ImageInput v-model="user.avatar" :error="errors[0]" />
|
||||
<!--Avatar-->
|
||||
<ValidationProvider tag="div" mode="passive" name="avatar" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_page_user.create_user.avatar')" :error="errors[0]">
|
||||
<ImageInput v-model="user.avatar" :error="errors[0]" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</ValidationProvider>
|
||||
|
||||
<!--Email-->
|
||||
<!--Email-->
|
||||
<ValidationProvider tag="div" mode="passive" name="email" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('page_registration.label_email')" :error="errors[0]">
|
||||
<input v-model="user.email" :placeholder="$t('admin_page_user.create_user.label_email')" type="email" class="focus-border-theme input-dark" :class="{'border-red': errors[0]}"/>
|
||||
<input
|
||||
v-model="user.email"
|
||||
:placeholder="$t('admin_page_user.create_user.label_email')"
|
||||
type="email"
|
||||
class="focus-border-theme input-dark"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<!--Name-->
|
||||
<!--Name-->
|
||||
<ValidationProvider tag="div" mode="passive" name="user name" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('page_registration.label_name')" :error="errors[0]">
|
||||
<input v-model="user.name" :placeholder="$t('admin_page_user.create_user.label_name')" type="text" class="focus-border-theme input-dark" :class="{'border-red': errors[0]}"/>
|
||||
<input
|
||||
v-model="user.name"
|
||||
:placeholder="$t('admin_page_user.create_user.label_name')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<!--Password-->
|
||||
<!--Password-->
|
||||
<div class="flex space-x-4">
|
||||
<ValidationProvider tag="div" mode="passive" name="password" rules="required" v-slot="{ errors }" class="w-full">
|
||||
<AppInputText :title="$t('page_registration.label_pass')" :error="errors[0]">
|
||||
<input v-model="user.password" :placeholder="$t('page_registration.placeholder_pass')" type="password" class="focus-border-theme input-dark" :class="{'border-red': errors[0]}"/>
|
||||
<input
|
||||
v-model="user.password"
|
||||
:placeholder="$t('page_registration.placeholder_pass')"
|
||||
type="password"
|
||||
class="focus-border-theme input-dark"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="password confirm" rules="required" v-slot="{ errors }" class="w-full">
|
||||
<AppInputText :title="$t('page_registration.label_confirm_pass')" :error="errors[0]">
|
||||
<input v-model="user.password_confirmation" :placeholder="$t('admin_page_user.create_user.label_conf_pass')" type="password" class="focus-border-theme input-dark" :class="{'border-red': errors[0]}"/>
|
||||
<input
|
||||
v-model="user.password_confirmation"
|
||||
:placeholder="$t('admin_page_user.create_user.label_conf_pass')"
|
||||
type="password"
|
||||
class="focus-border-theme input-dark"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -41,17 +65,25 @@
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>{{ $t('admin_page_user.create_user.group_settings') }}</FormLabel>
|
||||
|
||||
<!--User Role-->
|
||||
<!--User Role-->
|
||||
<ValidationProvider tag="div" mode="passive" name="permission" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_page_user.select_role')" :error="errors[0]">
|
||||
<SelectInput v-model="user.role" :options="$translateSelectOptions(roles)" :placeholder="$t('admin_page_user.select_role')" :isError="errors[0]"/>
|
||||
<SelectInput v-model="user.role" :options="$translateSelectOptions(roles)" :placeholder="$t('admin_page_user.select_role')" :isError="errors[0]" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<!--Storage Capacity-->
|
||||
<!--Storage Capacity-->
|
||||
<ValidationProvider tag="div" mode="passive" name="storage capacity" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('admin_page_user.label_change_capacity')" :error="errors[0]">
|
||||
<input v-model="user.max_storage_amount" min="1" max="999999999" :placeholder="$t('admin_page_user.label_change_capacity')" type="number" class="focus-border-theme input-dark" :class="{'border-red': errors[0]}"/>
|
||||
<input
|
||||
v-model="user.max_storage_amount"
|
||||
min="1"
|
||||
max="999999999"
|
||||
:placeholder="$t('admin_page_user.label_change_capacity')"
|
||||
type="number"
|
||||
class="focus-border-theme input-dark"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -64,139 +96,133 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AppInputText from "../../../components/Admin/AppInputText";
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import SelectInput from "../../../components/Others/Forms/SelectInput";
|
||||
import ImageInput from "../../../components/Others/Forms/ImageInput";
|
||||
import FormLabel from "../../../components/Others/Forms/FormLabel";
|
||||
import MobileHeader from "../../../components/Mobile/MobileHeader";
|
||||
import SectionTitle from "../../../components/Others/SectionTitle";
|
||||
import ButtonBase from "../../../components/FilesView/ButtonBase";
|
||||
import PageHeader from "../../../components/Others/PageHeader";
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import { mapGetters } from 'vuex'
|
||||
import {events} from '../../../bus'
|
||||
import axios from 'axios'
|
||||
import AppInputText from '../../../components/Admin/AppInputText'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import SelectInput from '../../../components/Others/Forms/SelectInput'
|
||||
import ImageInput from '../../../components/Others/Forms/ImageInput'
|
||||
import FormLabel from '../../../components/Others/Forms/FormLabel'
|
||||
import MobileHeader from '../../../components/Mobile/MobileHeader'
|
||||
import SectionTitle from '../../../components/Others/SectionTitle'
|
||||
import ButtonBase from '../../../components/FilesView/ButtonBase'
|
||||
import PageHeader from '../../../components/Others/PageHeader'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { events } from '../../../bus'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'Profile',
|
||||
components: {
|
||||
AppInputText,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SectionTitle,
|
||||
MobileHeader,
|
||||
SelectInput,
|
||||
ButtonBase,
|
||||
ImageInput,
|
||||
PageHeader,
|
||||
FormLabel,
|
||||
required,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['roles']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
user: {
|
||||
role: '',
|
||||
avatar: undefined,
|
||||
name: '',
|
||||
email: '',
|
||||
password: '',
|
||||
password_confirmation: '',
|
||||
max_storage_amount: 5,
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async createUser() {
|
||||
export default {
|
||||
name: 'Profile',
|
||||
components: {
|
||||
AppInputText,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SectionTitle,
|
||||
MobileHeader,
|
||||
SelectInput,
|
||||
ButtonBase,
|
||||
ImageInput,
|
||||
PageHeader,
|
||||
FormLabel,
|
||||
required,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['roles']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
user: {
|
||||
role: '',
|
||||
avatar: undefined,
|
||||
name: '',
|
||||
email: '',
|
||||
password: '',
|
||||
password_confirmation: '',
|
||||
max_storage_amount: 5,
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async createUser() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.createUser.validate()
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.createUser.validate();
|
||||
if (!isValid) return
|
||||
|
||||
if (!isValid) return;
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
// Create form
|
||||
let formData = new FormData()
|
||||
|
||||
// Create form
|
||||
let formData = new FormData()
|
||||
// Add image to form
|
||||
formData.append('name', this.user.name)
|
||||
formData.append('role', this.user.role)
|
||||
formData.append('email', this.user.email)
|
||||
formData.append('password', this.user.password)
|
||||
formData.append('max_storage_amount', this.user.max_storage_amount)
|
||||
formData.append('password_confirmation', this.user.password_confirmation)
|
||||
|
||||
// Add image to form
|
||||
formData.append('name', this.user.name)
|
||||
formData.append('role', this.user.role)
|
||||
formData.append('email', this.user.email)
|
||||
formData.append('password', this.user.password)
|
||||
formData.append('max_storage_amount', this.user.max_storage_amount)
|
||||
formData.append('password_confirmation', this.user.password_confirmation)
|
||||
// Append avatar if exist
|
||||
if (this.user.avatar) formData.append('avatar', this.user.avatar)
|
||||
|
||||
// Append avatar if exist
|
||||
if (this.user.avatar)
|
||||
formData.append('avatar', this.user.avatar)
|
||||
// Send request to get user token
|
||||
axios
|
||||
.post('/api/admin/users', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
// Send request to get user token
|
||||
axios
|
||||
.post('/api/admin/users', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
}
|
||||
// Show toaster
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.created_user'),
|
||||
})
|
||||
.then(response => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
// Show toaster
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.created_user'),
|
||||
})
|
||||
|
||||
// Go to User page
|
||||
this.$router.push({name: 'UserDetail', params: {id: response.data.data.id}})
|
||||
// Go to User page
|
||||
this.$router.push({
|
||||
name: 'UserDetail',
|
||||
params: { id: response.data.data.id },
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
// Validation errors
|
||||
if (error.response.status == 422) {
|
||||
|
||||
// Email validation error
|
||||
if (error.response.data.errors['email']) {
|
||||
|
||||
this.$refs.createUser.setErrors({
|
||||
'email': error.response.data.errors['email']
|
||||
});
|
||||
}
|
||||
|
||||
// Password validation error
|
||||
if (error.response.data.errors['password']) {
|
||||
|
||||
this.$refs.createUser.setErrors({
|
||||
'password': error.response.data.errors['password']
|
||||
});
|
||||
}
|
||||
|
||||
// Password validation error
|
||||
if (error.response.data.errors['max_storage_amount']) {
|
||||
|
||||
this.$refs.createUser.setErrors({
|
||||
'storage capacity': this.$t('errors.capacity_digit')
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
||||
events.$emit('alert:open', {
|
||||
title: this.$t('popup_error.title'),
|
||||
message: this.$t('popup_error.message'),
|
||||
})
|
||||
.catch((error) => {
|
||||
// Validation errors
|
||||
if (error.response.status == 422) {
|
||||
// Email validation error
|
||||
if (error.response.data.errors['email']) {
|
||||
this.$refs.createUser.setErrors({
|
||||
email: error.response.data.errors['email'],
|
||||
})
|
||||
}
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
// Password validation error
|
||||
if (error.response.data.errors['password']) {
|
||||
this.$refs.createUser.setErrors({
|
||||
password: error.response.data.errors['password'],
|
||||
})
|
||||
}
|
||||
|
||||
// Password validation error
|
||||
if (error.response.data.errors['max_storage_amount']) {
|
||||
this.$refs.createUser.setErrors({
|
||||
'storage capacity': this.$t('errors.capacity_digit'),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
events.$emit('alert:open', {
|
||||
title: this.$t('popup_error.title'),
|
||||
message: this.$t('popup_error.message'),
|
||||
})
|
||||
}
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,123 +1,125 @@
|
||||
<template>
|
||||
<div v-if="user" class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('user_box_delete.title') }}
|
||||
</FormLabel>
|
||||
<ValidationObserver ref="deleteUser" @submit.prevent="deleteUser" v-slot="{ invalid }" tag="form">
|
||||
<ValidationProvider tag="div" v-slot="{ errors }" mode="passive" name="User name" rules="required">
|
||||
<AppInputText :title="$t('admin_page_user.label_delete_user', {user: user.data.relationships.settings.data.attributes.name})" :description="$t('user_box_delete.description')" :error="errors[0]" :is-last="true">
|
||||
<div class="sm:flex sm:space-x-4 sm:space-y-0 space-y-4">
|
||||
<input v-model="userName"
|
||||
:placeholder="$t('admin_page_user.placeholder_delete_user')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
:class="{'border-red': errors[0]}"
|
||||
/>
|
||||
<ButtonBase :loading="isSendingRequest" :disabled="isSendingRequest" type="submit" button-style="danger" class="sm:w-auto w-full">
|
||||
{{ $t('admin_page_user.delete_user') }}
|
||||
</ButtonBase>
|
||||
</div>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
<div v-if="user" class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('user_box_delete.title') }}
|
||||
</FormLabel>
|
||||
<ValidationObserver ref="deleteUser" @submit.prevent="deleteUser" v-slot="{ invalid }" tag="form">
|
||||
<ValidationProvider tag="div" v-slot="{ errors }" mode="passive" name="User name" rules="required">
|
||||
<AppInputText
|
||||
:title="
|
||||
$t('admin_page_user.label_delete_user', {
|
||||
user: user.data.relationships.settings.data.attributes.name,
|
||||
})
|
||||
"
|
||||
:description="$t('user_box_delete.description')"
|
||||
:error="errors[0]"
|
||||
:is-last="true"
|
||||
>
|
||||
<div class="space-y-4 sm:flex sm:space-x-4 sm:space-y-0">
|
||||
<input
|
||||
v-model="userName"
|
||||
:placeholder="$t('admin_page_user.placeholder_delete_user')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
<ButtonBase :loading="isSendingRequest" :disabled="isSendingRequest" type="submit" button-style="danger" class="w-full sm:w-auto">
|
||||
{{ $t('admin_page_user.delete_user') }}
|
||||
</ButtonBase>
|
||||
</div>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AppInputText from "../../../../components/Admin/AppInputText";
|
||||
import FormLabel from "../../../../components/Others/Forms/FormLabel";
|
||||
import InfoBox from "../../../../components/Others/Forms/InfoBox";
|
||||
import AppInputText from '../../../../components/Admin/AppInputText'
|
||||
import FormLabel from '../../../../components/Others/Forms/FormLabel'
|
||||
import InfoBox from '../../../../components/Others/Forms/InfoBox'
|
||||
|
||||
import PageTabGroup from "../../../../components/Others/Layout/PageTabGroup";
|
||||
import PageTab from "../../../../components/Others/Layout/PageTab";
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import ButtonBase from "../../../../components/FilesView/ButtonBase";
|
||||
import SetupBox from "../../../../components/Others/Forms/SetupBox";
|
||||
import {required, is} from 'vee-validate/dist/rules'
|
||||
import {events} from '../../../../bus'
|
||||
import axios from 'axios'
|
||||
import PageTabGroup from '../../../../components/Others/Layout/PageTabGroup'
|
||||
import PageTab from '../../../../components/Others/Layout/PageTab'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import ButtonBase from '../../../../components/FilesView/ButtonBase'
|
||||
import SetupBox from '../../../../components/Others/Forms/SetupBox'
|
||||
import { required, is } from 'vee-validate/dist/rules'
|
||||
import { events } from '../../../../bus'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'UserDelete',
|
||||
props: [
|
||||
'user'
|
||||
],
|
||||
components: {
|
||||
AppInputText,
|
||||
FormLabel,
|
||||
InfoBox,
|
||||
PageTabGroup,
|
||||
PageTab,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
ButtonBase,
|
||||
SetupBox,
|
||||
required,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isSendingRequest: false,
|
||||
isLoading: false,
|
||||
userName: '',
|
||||
export default {
|
||||
name: 'UserDelete',
|
||||
props: ['user'],
|
||||
components: {
|
||||
AppInputText,
|
||||
FormLabel,
|
||||
InfoBox,
|
||||
PageTabGroup,
|
||||
PageTab,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
ButtonBase,
|
||||
SetupBox,
|
||||
required,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isSendingRequest: false,
|
||||
isLoading: false,
|
||||
userName: '',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async deleteUser() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.deleteUser.validate()
|
||||
|
||||
if (!isValid) return
|
||||
|
||||
if (this.userName !== this.user.data.relationships.settings.data.attributes.name) {
|
||||
this.$refs.deleteUser.setErrors({
|
||||
'User name': 'The user name is not the same.',
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async deleteUser() {
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.deleteUser.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
if (this.userName !== this.user.data.relationships.settings.data.attributes.name) {
|
||||
|
||||
this.$refs.deleteUser.setErrors({
|
||||
'User name': 'The user name is not the same.'
|
||||
});
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
this.isSendingRequest = true
|
||||
|
||||
axios
|
||||
.post(this.$store.getters.api + '/admin/users/' + this.$route.params.id + '/delete',
|
||||
{
|
||||
name: this.userName,
|
||||
_method: 'delete'
|
||||
}
|
||||
)
|
||||
.then((response) => {
|
||||
|
||||
if (response.status === 202) {
|
||||
events.$emit('alert:open', {
|
||||
emoji: '☹️',
|
||||
title: this.$t('popup_deleted_user_aborted.title'),
|
||||
message: this.$t('popup_deleted_user_aborted.message'),
|
||||
})
|
||||
}
|
||||
|
||||
if (response.status === 204) {
|
||||
events.$emit('success:open', {
|
||||
emoji: '👍',
|
||||
title: this.$t('popup_deleted_user.title'),
|
||||
message: this.$t('popup_deleted_user.message'),
|
||||
})
|
||||
|
||||
this.$router.push({name: 'Users'})
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.isSendingRequest = true
|
||||
|
||||
axios
|
||||
.post(this.$store.getters.api + '/admin/users/' + this.$route.params.id + '/delete', {
|
||||
name: this.userName,
|
||||
_method: 'delete',
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status === 202) {
|
||||
events.$emit('alert:open', {
|
||||
title: this.$t('popup_error.title'),
|
||||
message: this.$t('popup_error.message'),
|
||||
emoji: '☹️',
|
||||
title: this.$t('popup_deleted_user_aborted.title'),
|
||||
message: this.$t('popup_deleted_user_aborted.message'),
|
||||
})
|
||||
}
|
||||
|
||||
if (response.status === 204) {
|
||||
events.$emit('success:open', {
|
||||
emoji: '👍',
|
||||
title: this.$t('popup_deleted_user.title'),
|
||||
message: this.$t('popup_deleted_user.message'),
|
||||
})
|
||||
|
||||
this.$router.push({ name: 'Users' })
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
events.$emit('alert:open', {
|
||||
title: this.$t('popup_error.title'),
|
||||
message: this.$t('popup_error.message'),
|
||||
})
|
||||
.finally(() => {
|
||||
this.isSendingRequest = false
|
||||
})
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.isSendingRequest = false
|
||||
})
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -7,193 +7,197 @@
|
||||
</FormLabel>
|
||||
<ValidationObserver ref="changeRole" @submit.prevent="changeRole" v-slot="{ invalid }" tag="form">
|
||||
<ValidationProvider tag="div" v-slot="{ errors }" mode="passive" name="Role" rules="required">
|
||||
<AppInputText :title="$t('admin_page_user.select_role')" :description="$t('user_box_role.description')" :error="errors[0]" :is-last="true">
|
||||
<div class="sm:flex sm:space-x-4 sm:space-y-0 space-y-4">
|
||||
<SelectInput v-model="userRole" :options="$translateSelectOptions(roles)" :placeholder="$t('admin_page_user.select_role')" :isError="errors[0]" />
|
||||
<ButtonBase :loading="isSendingRequest" :disabled="isSendingRequest" type="submit" button-style="theme" class="sm:w-auto w-full">
|
||||
{{ $t('admin_page_user.save_role') }}
|
||||
</ButtonBase>
|
||||
</div>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('admin_page_user.select_role')" :description="$t('user_box_role.description')" :error="errors[0]" :is-last="true">
|
||||
<div class="space-y-4 sm:flex sm:space-x-4 sm:space-y-0">
|
||||
<SelectInput v-model="userRole" :options="$translateSelectOptions(roles)" :placeholder="$t('admin_page_user.select_role')" :isError="errors[0]" />
|
||||
<ButtonBase :loading="isSendingRequest" :disabled="isSendingRequest" type="submit" button-style="theme" class="w-full sm:w-auto">
|
||||
{{ $t('admin_page_user.save_role') }}
|
||||
</ButtonBase>
|
||||
</div>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('admin_page_user.label_person_info') }}
|
||||
</FormLabel>
|
||||
{{ $t('admin_page_user.label_person_info') }}
|
||||
</FormLabel>
|
||||
|
||||
<!--Name-->
|
||||
<div class="md:flex justify-items md:space-x-4">
|
||||
<AppInputText :title="$t('First Name')" class="w-full">
|
||||
<input
|
||||
disabled
|
||||
:value="user.data.relationships.settings.data.attributes.first_name"
|
||||
:placeholder="$t('page_registration.placeholder_name')"
|
||||
type="text"
|
||||
class="disabled:text-gray-900 disabled:opacity-100 focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('Last Name')" class="w-full">
|
||||
<input
|
||||
disabled
|
||||
:value="user.data.relationships.settings.data.attributes.last_name"
|
||||
:placeholder="$t('page_registration.placeholder_name')"
|
||||
type="text"
|
||||
class="disabled:text-gray-900 disabled:opacity-100 focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
<!--Name-->
|
||||
<div class="justify-items md:flex md:space-x-4">
|
||||
<AppInputText :title="$t('First Name')" class="w-full">
|
||||
<input
|
||||
disabled
|
||||
:value="user.data.relationships.settings.data.attributes.first_name"
|
||||
:placeholder="$t('page_registration.placeholder_name')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark disabled:text-gray-900 disabled:opacity-100"
|
||||
/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('Last Name')" class="w-full">
|
||||
<input
|
||||
disabled
|
||||
:value="user.data.relationships.settings.data.attributes.last_name"
|
||||
:placeholder="$t('page_registration.placeholder_name')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark disabled:text-gray-900 disabled:opacity-100"
|
||||
/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
|
||||
<AppInputText :title="$t('page_registration.label_name')" :is-last="true">
|
||||
<input :value="user.data.relationships.settings.data.attributes.name"
|
||||
:placeholder="$t('page_registration.placeholder_name')"
|
||||
type="text"
|
||||
class="disabled:text-gray-900 disabled:opacity-100 focus-border-theme input-dark"
|
||||
disabled
|
||||
/>
|
||||
<input
|
||||
:value="user.data.relationships.settings.data.attributes.name"
|
||||
:placeholder="$t('page_registration.placeholder_name')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark disabled:text-gray-900 disabled:opacity-100"
|
||||
disabled
|
||||
/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>{{ $t('user_settings.title_billing') }}</FormLabel>
|
||||
<AppInputText :title="$t('user_settings.name')">
|
||||
<input :value="user.data.relationships.settings.data.attributes.name"
|
||||
type="text"
|
||||
class="disabled:text-gray-900 disabled:opacity-100 focus-border-theme input-dark"
|
||||
disabled
|
||||
/>
|
||||
<input
|
||||
:value="user.data.relationships.settings.data.attributes.name"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark disabled:text-gray-900 disabled:opacity-100"
|
||||
disabled
|
||||
/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('user_settings.address')">
|
||||
<input :value="user.data.relationships.settings.data.attributes.address"
|
||||
type="text"
|
||||
disabled
|
||||
class="disabled:text-gray-900 disabled:opacity-100 focus-border-theme input-dark"
|
||||
/>
|
||||
<input
|
||||
:value="user.data.relationships.settings.data.attributes.address"
|
||||
type="text"
|
||||
disabled
|
||||
class="focus-border-theme input-dark disabled:text-gray-900 disabled:opacity-100"
|
||||
/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('user_settings.country')">
|
||||
<input :value="user.data.relationships.settings.data.attributes.country"
|
||||
type="text"
|
||||
disabled
|
||||
class="disabled:text-gray-900 disabled:opacity-100 focus-border-theme input-dark"
|
||||
/>
|
||||
<input
|
||||
:value="user.data.relationships.settings.data.attributes.country"
|
||||
type="text"
|
||||
disabled
|
||||
class="focus-border-theme input-dark disabled:text-gray-900 disabled:opacity-100"
|
||||
/>
|
||||
</AppInputText>
|
||||
<div class="flex space-x-4">
|
||||
<AppInputText :title="$t('user_settings.city')" class="w-full">
|
||||
<input :value="user.data.relationships.settings.data.attributes.city"
|
||||
type="text"
|
||||
disabled
|
||||
class="disabled:text-gray-900 disabled:opacity-100 focus-border-theme input-dark"
|
||||
/>
|
||||
<input
|
||||
:value="user.data.relationships.settings.data.attributes.city"
|
||||
type="text"
|
||||
disabled
|
||||
class="focus-border-theme input-dark disabled:text-gray-900 disabled:opacity-100"
|
||||
/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('user_settings.postal_code')" class="w-full">
|
||||
<input :value="user.data.relationships.settings.data.attributes.postal_code"
|
||||
type="text"
|
||||
disabled
|
||||
class="disabled:text-gray-900 disabled:opacity-100 focus-border-theme input-dark"
|
||||
/>
|
||||
<input
|
||||
:value="user.data.relationships.settings.data.attributes.postal_code"
|
||||
type="text"
|
||||
disabled
|
||||
class="focus-border-theme input-dark disabled:text-gray-900 disabled:opacity-100"
|
||||
/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
<AppInputText :title="$t('user_settings.state')">
|
||||
<input :value="user.data.relationships.settings.data.attributes.state"
|
||||
type="text"
|
||||
disabled
|
||||
class="disabled:text-gray-900 disabled:opacity-100 focus-border-theme input-dark"
|
||||
/>
|
||||
<input
|
||||
:value="user.data.relationships.settings.data.attributes.state"
|
||||
type="text"
|
||||
disabled
|
||||
class="focus-border-theme input-dark disabled:text-gray-900 disabled:opacity-100"
|
||||
/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('user_settings.phone_number')" :is-last="true">
|
||||
<input :value="user.data.relationships.settings.data.attributes.phone_number"
|
||||
type="text"
|
||||
disabled
|
||||
class="disabled:text-gray-900 disabled:opacity-100 focus-border-theme input-dark"
|
||||
/>
|
||||
<input
|
||||
:value="user.data.relationships.settings.data.attributes.phone_number"
|
||||
type="text"
|
||||
disabled
|
||||
class="focus-border-theme input-dark disabled:text-gray-900 disabled:opacity-100"
|
||||
/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
</PageTab>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AppInputText from "../../../../components/Admin/AppInputText";
|
||||
import InfoBox from "../../../../components/Others/Forms/InfoBox";
|
||||
import PageTabGroup from "../../../../components/Others/Layout/PageTabGroup";
|
||||
import PageTab from "../../../../components/Others/Layout/PageTab";
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import SelectInput from "../../../../components/Others/Forms/SelectInput";
|
||||
import FormLabel from "../../../../components/Others/Forms/FormLabel";
|
||||
import ButtonBase from "../../../../components/FilesView/ButtonBase";
|
||||
import SetupBox from "../../../../components/Others/Forms/SetupBox";
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {mapGetters} from 'vuex'
|
||||
import {events} from '../../../../bus'
|
||||
import axios from 'axios'
|
||||
import AppInputText from '../../../../components/Admin/AppInputText'
|
||||
import InfoBox from '../../../../components/Others/Forms/InfoBox'
|
||||
import PageTabGroup from '../../../../components/Others/Layout/PageTabGroup'
|
||||
import PageTab from '../../../../components/Others/Layout/PageTab'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import SelectInput from '../../../../components/Others/Forms/SelectInput'
|
||||
import FormLabel from '../../../../components/Others/Forms/FormLabel'
|
||||
import ButtonBase from '../../../../components/FilesView/ButtonBase'
|
||||
import SetupBox from '../../../../components/Others/Forms/SetupBox'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { events } from '../../../../bus'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'UserDetail',
|
||||
props: [
|
||||
'user'
|
||||
],
|
||||
components: {
|
||||
AppInputText,
|
||||
PageTabGroup,
|
||||
PageTab,
|
||||
InfoBox,
|
||||
FormLabel,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SelectInput,
|
||||
ButtonBase,
|
||||
SetupBox,
|
||||
required,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['roles', 'config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
isSendingRequest: false,
|
||||
userRole: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async changeRole() {
|
||||
export default {
|
||||
name: 'UserDetail',
|
||||
props: ['user'],
|
||||
components: {
|
||||
AppInputText,
|
||||
PageTabGroup,
|
||||
PageTab,
|
||||
InfoBox,
|
||||
FormLabel,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SelectInput,
|
||||
ButtonBase,
|
||||
SetupBox,
|
||||
required,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['roles', 'config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
isSendingRequest: false,
|
||||
userRole: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async changeRole() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.changeRole.validate()
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.changeRole.validate();
|
||||
if (!isValid) return
|
||||
|
||||
if (!isValid) return;
|
||||
this.isSendingRequest = true
|
||||
|
||||
this.isSendingRequest = true
|
||||
// Send request to get user reset link
|
||||
axios
|
||||
.post(this.$store.getters.api + '/admin/users/' + this.$route.params.id + '/role', {
|
||||
attributes: {
|
||||
role: this.userRole,
|
||||
},
|
||||
_method: 'patch',
|
||||
})
|
||||
.then(() => {
|
||||
// Reset errors
|
||||
this.$refs.changeRole.reset()
|
||||
|
||||
// Send request to get user reset link
|
||||
axios
|
||||
.post(this.$store.getters.api + '/admin/users/' + this.$route.params.id + '/role', {
|
||||
attributes: {
|
||||
role: this.userRole,
|
||||
},
|
||||
_method: 'patch'
|
||||
this.$emit('reload-user')
|
||||
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.changed_user'),
|
||||
})
|
||||
.then(() => {
|
||||
|
||||
// Reset errors
|
||||
this.$refs.changeRole.reset()
|
||||
|
||||
this.$emit('reload-user')
|
||||
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.changed_user'),
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
events.$emit('alert:open', {
|
||||
title: this.$t('popup_error.title'),
|
||||
message: this.$t('popup_error.message'),
|
||||
})
|
||||
.catch(() => {
|
||||
events.$emit('alert:open', {
|
||||
title: this.$t('popup_error.title'),
|
||||
message: this.$t('popup_error.message'),
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
this.isSendingRequest = false
|
||||
})
|
||||
}
|
||||
})
|
||||
.finally(() => {
|
||||
this.isSendingRequest = false
|
||||
})
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,91 +1,85 @@
|
||||
<template>
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Subscription') }}
|
||||
</FormLabel>
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Subscription') }}
|
||||
</FormLabel>
|
||||
|
||||
<b class="sm:text-3xl text-xl font-extrabold -mt-3 block mb-0.5">
|
||||
{{ status }}
|
||||
</b>
|
||||
<b class="-mt-3 mb-0.5 block text-xl font-extrabold sm:text-3xl">
|
||||
{{ status }}
|
||||
</b>
|
||||
|
||||
<b class="mb-3 block text-sm text-gray-400 mb-8">
|
||||
{{ subscription.relationships.plan.data.attributes.name }} / {{ price }}
|
||||
</b>
|
||||
<b class="mb-3 mb-8 block text-sm text-gray-400">
|
||||
{{ subscription.relationships.plan.data.attributes.name }} /
|
||||
{{ price }}
|
||||
</b>
|
||||
|
||||
<div v-for="(limit, i) in limitations" :key="i" :class="{'mb-6': (Object.keys(limitations).length - 1) !== i}">
|
||||
<b class="mb-3 block text-sm text-gray-400">
|
||||
{{ limit.message }}
|
||||
</b>
|
||||
<ProgressLine :data="limit.distribution" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-for="(limit, i) in limitations" :key="i" :class="{ 'mb-6': Object.keys(limitations).length - 1 !== i }">
|
||||
<b class="mb-3 block text-sm text-gray-400">
|
||||
{{ limit.message }}
|
||||
</b>
|
||||
<ProgressLine :data="limit.distribution" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import FormLabel from "../../../../components/Others/Forms/FormLabel";
|
||||
import ProgressLine from "../../../../components/Admin/ProgressLine"
|
||||
import {mapGetters} from "vuex";
|
||||
import FormLabel from '../../../../components/Others/Forms/FormLabel'
|
||||
import ProgressLine from '../../../../components/Admin/ProgressLine'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'UserFixedSubscription',
|
||||
props: [
|
||||
'subscription',
|
||||
'user',
|
||||
],
|
||||
components: {
|
||||
ProgressLine,
|
||||
FormLabel,
|
||||
},
|
||||
computed: {
|
||||
status() {
|
||||
return {
|
||||
'active': `Active until ${this.subscription.attributes.renews_at}`,
|
||||
'cancelled': `Active until ${this.subscription.attributes.ends_at}`,
|
||||
}[this.subscription.attributes.status]
|
||||
},
|
||||
price() {
|
||||
return {
|
||||
'month': `${this.subscription.relationships.plan.data.attributes.price} Per Month`,
|
||||
'year': `${this.subscription.relationships.plan.data.attributes.price} Per Year`,
|
||||
}[this.subscription.relationships.plan.data.attributes.interval]
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
limitations: []
|
||||
}
|
||||
},
|
||||
created() {
|
||||
Object
|
||||
.entries(this.user.data.meta.limitations)
|
||||
.map(([key, item]) => {
|
||||
export default {
|
||||
name: 'UserFixedSubscription',
|
||||
props: ['subscription', 'user'],
|
||||
components: {
|
||||
ProgressLine,
|
||||
FormLabel,
|
||||
},
|
||||
computed: {
|
||||
status() {
|
||||
return {
|
||||
active: `Active until ${this.subscription.attributes.renews_at}`,
|
||||
cancelled: `Active until ${this.subscription.attributes.ends_at}`,
|
||||
}[this.subscription.attributes.status]
|
||||
},
|
||||
price() {
|
||||
return {
|
||||
month: `${this.subscription.relationships.plan.data.attributes.price} Per Month`,
|
||||
year: `${this.subscription.relationships.plan.data.attributes.price} Per Year`,
|
||||
}[this.subscription.relationships.plan.data.attributes.interval]
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
limitations: [],
|
||||
}
|
||||
},
|
||||
created() {
|
||||
Object.entries(this.user.data.meta.limitations).map(([key, item]) => {
|
||||
let payload = {
|
||||
color: {
|
||||
max_storage_amount: 'warning',
|
||||
max_team_members: 'purple',
|
||||
},
|
||||
message: {
|
||||
max_storage_amount: `Total ${item.use} of ${item.total} Used`,
|
||||
max_team_members: `Total ${item.use} of ${item.total} Members`,
|
||||
},
|
||||
title: {
|
||||
max_storage_amount: `Storage`,
|
||||
max_team_members: `Team Members`,
|
||||
},
|
||||
}
|
||||
|
||||
let payload = {
|
||||
color: {
|
||||
'max_storage_amount': 'warning',
|
||||
'max_team_members': 'purple',
|
||||
},
|
||||
message: {
|
||||
'max_storage_amount': `Total ${item.use} of ${item.total} Used`,
|
||||
'max_team_members': `Total ${item.use} of ${item.total} Members`,
|
||||
},
|
||||
title: {
|
||||
'max_storage_amount': `Storage`,
|
||||
'max_team_members': `Team Members`,
|
||||
}
|
||||
}
|
||||
|
||||
this.limitations.push({
|
||||
message: payload.message[key],
|
||||
distribution: [
|
||||
{
|
||||
progress: item.percentage,
|
||||
color: payload.color[key],
|
||||
title: payload.title[key],
|
||||
}
|
||||
]
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
this.limitations.push({
|
||||
message: payload.message[key],
|
||||
distribution: [
|
||||
{
|
||||
progress: item.percentage,
|
||||
color: payload.color[key],
|
||||
title: payload.title[key],
|
||||
},
|
||||
],
|
||||
})
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,150 +1,145 @@
|
||||
<template>
|
||||
<div>
|
||||
<!--Balance-->
|
||||
<div class="card shadow-card">
|
||||
<FormLabel icon="hard-drive">
|
||||
{{ $t('Balance') }}
|
||||
</FormLabel>
|
||||
<div>
|
||||
<!--Balance-->
|
||||
<div class="card shadow-card">
|
||||
<FormLabel icon="hard-drive">
|
||||
{{ $t('Balance') }}
|
||||
</FormLabel>
|
||||
|
||||
<b class="sm:text-3xl text-2xl font-extrabold -mt-3 block mb-0.5">
|
||||
{{ user.data.relationships.balance.data.attributes.formatted }}
|
||||
</b>
|
||||
<b class="-mt-3 mb-0.5 block text-2xl font-extrabold sm:text-3xl">
|
||||
{{ user.data.relationships.balance.data.attributes.formatted }}
|
||||
</b>
|
||||
|
||||
<ValidationObserver ref="creditUserBalance" @submit.prevent="increaseBalance" v-slot="{ invalid }" tag="form" class="mt-6">
|
||||
<ValidationProvider tag="div" v-slot="{ errors }" mode="passive" name="Balance Amount" rules="required">
|
||||
<AppInputText :description="$t('User balance will be increased for the amount above.')" :error="errors[0]" :is-last="true">
|
||||
<div class="sm:flex sm:space-x-4 sm:space-y-0 space-y-4">
|
||||
<input v-model="balanceAmount"
|
||||
:placeholder="$t('Increase user balance for...')"
|
||||
type="number"
|
||||
min="1"
|
||||
max="999999999"
|
||||
class="focus-border-theme input-dark"
|
||||
:class="{'border-red': errors[0]}"
|
||||
/>
|
||||
<ButtonBase type="submit" button-style="theme" class="sm:w-auto w-full"
|
||||
:loading="isUpdatingBalanceAmount"
|
||||
:disabled="isUpdatingBalanceAmount"
|
||||
>
|
||||
{{ $t('Increase Balance') }}
|
||||
</ButtonBase>
|
||||
</div>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
<ValidationObserver ref="creditUserBalance" @submit.prevent="increaseBalance" v-slot="{ invalid }" tag="form" class="mt-6">
|
||||
<ValidationProvider tag="div" v-slot="{ errors }" mode="passive" name="Balance Amount" rules="required">
|
||||
<AppInputText :description="$t('User balance will be increased for the amount above.')" :error="errors[0]" :is-last="true">
|
||||
<div class="space-y-4 sm:flex sm:space-x-4 sm:space-y-0">
|
||||
<input
|
||||
v-model="balanceAmount"
|
||||
:placeholder="$t('Increase user balance for...')"
|
||||
type="number"
|
||||
min="1"
|
||||
max="999999999"
|
||||
class="focus-border-theme input-dark"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
<ButtonBase type="submit" button-style="theme" class="w-full sm:w-auto" :loading="isUpdatingBalanceAmount" :disabled="isUpdatingBalanceAmount">
|
||||
{{ $t('Increase Balance') }}
|
||||
</ButtonBase>
|
||||
</div>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
|
||||
<!--Usage Estimates-->
|
||||
<div class="card shadow-card">
|
||||
<FormLabel icon="hard-drive">
|
||||
{{ $t('Usage Estimates') }}
|
||||
</FormLabel>
|
||||
<!--Usage Estimates-->
|
||||
<div class="card shadow-card">
|
||||
<FormLabel icon="hard-drive">
|
||||
{{ $t('Usage Estimates') }}
|
||||
</FormLabel>
|
||||
|
||||
<b class="sm:text-3xl text-2xl font-extrabold -mt-3 block mb-0.5">
|
||||
{{ user.data.meta.usages.costEstimate }}
|
||||
</b>
|
||||
<b class="-mt-3 mb-0.5 block text-2xl font-extrabold sm:text-3xl">
|
||||
{{ user.data.meta.usages.costEstimate }}
|
||||
</b>
|
||||
|
||||
<b class="mb-3 block text-sm text-gray-400 mb-5">
|
||||
{{ user.data.relationships.subscription.data.attributes.updated_at }} {{ $t('till now') }}
|
||||
</b>
|
||||
<b class="mb-3 mb-5 block text-sm text-gray-400">
|
||||
{{ user.data.relationships.subscription.data.attributes.updated_at }}
|
||||
{{ $t('till now') }}
|
||||
</b>
|
||||
|
||||
<div>
|
||||
<div class="flex items-center justify-between py-2 border-b dark:border-opacity-5 border-light border-dashed" v-for="(usage, i) in user.data.meta.usages.featureEstimates" :key="i">
|
||||
<div class="w-2/4 leading-none">
|
||||
<b class="text-sm font-bold leading-none">
|
||||
{{ $t(usage.feature) }}
|
||||
</b>
|
||||
<small class="text-xs text-gray-500 pt-2 leading-none block">
|
||||
{{ $t(`feature_usage_desc_${usage.feature}`) }}
|
||||
</small>
|
||||
</div>
|
||||
<div class="text-left w-1/4">
|
||||
<span class="text-sm font-bold text-gray-560">
|
||||
{{ usage.usage }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="text-right w-1/4">
|
||||
<span class="text-sm font-bold text-theme">
|
||||
{{ usage.cost }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="flex items-center justify-between border-b border-dashed border-light py-2 dark:border-opacity-5"
|
||||
v-for="(usage, i) in user.data.meta.usages.featureEstimates"
|
||||
:key="i"
|
||||
>
|
||||
<div class="w-2/4 leading-none">
|
||||
<b class="text-sm font-bold leading-none">
|
||||
{{ $t(usage.feature) }}
|
||||
</b>
|
||||
<small class="block pt-2 text-xs leading-none text-gray-500">
|
||||
{{ $t(`feature_usage_desc_${usage.feature}`) }}
|
||||
</small>
|
||||
</div>
|
||||
<div class="w-1/4 text-left">
|
||||
<span class="text-gray-560 text-sm font-bold">
|
||||
{{ usage.usage }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="w-1/4 text-right">
|
||||
<span class="text-theme text-sm font-bold">
|
||||
{{ usage.cost }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import AppInputText from "../../../../components/Admin/AppInputText"
|
||||
import FormLabel from "../../../../components/Others/Forms/FormLabel"
|
||||
import ButtonBase from "../../../../components/FilesView/ButtonBase"
|
||||
import ColorLabel from "../../../../components/Others/ColorLabel"
|
||||
import {mapGetters} from "vuex";
|
||||
import axios from "axios";
|
||||
import {events} from "../../../../bus";
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import AppInputText from '../../../../components/Admin/AppInputText'
|
||||
import FormLabel from '../../../../components/Others/Forms/FormLabel'
|
||||
import ButtonBase from '../../../../components/FilesView/ButtonBase'
|
||||
import ColorLabel from '../../../../components/Others/ColorLabel'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
import { events } from '../../../../bus'
|
||||
|
||||
export default {
|
||||
name: 'UserMeteredSubscription',
|
||||
props: [
|
||||
'subscription',
|
||||
'user',
|
||||
],
|
||||
components: {
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AppInputText,
|
||||
ButtonBase,
|
||||
ColorLabel,
|
||||
FormLabel,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
export default {
|
||||
name: 'UserMeteredSubscription',
|
||||
props: ['subscription', 'user'],
|
||||
components: {
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AppInputText,
|
||||
ButtonBase,
|
||||
ColorLabel,
|
||||
FormLabel,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([]),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
balanceAmount: undefined,
|
||||
isUpdatingBalanceAmount: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async increaseBalance() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.creditUserBalance.validate()
|
||||
|
||||
]),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
balanceAmount: undefined,
|
||||
isUpdatingBalanceAmount: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async increaseBalance() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.creditUserBalance.validate();
|
||||
if (!isValid) return
|
||||
|
||||
if (!isValid) return;
|
||||
this.isUpdatingBalanceAmount = true
|
||||
|
||||
this.isUpdatingBalanceAmount = true
|
||||
axios
|
||||
.post(`/api/subscriptions/admin/users/${this.user.data.id}/credit`, {
|
||||
amount: this.balanceAmount,
|
||||
})
|
||||
.then(() => {
|
||||
events.$emit('reload:user')
|
||||
|
||||
axios
|
||||
.post(`/api/subscriptions/admin/users/${this.user.data.id}/credit`, {
|
||||
amount: this.balanceAmount
|
||||
})
|
||||
.then(() => {
|
||||
events.$emit('reload:user')
|
||||
this.balanceAmount = undefined
|
||||
|
||||
this.balanceAmount = undefined
|
||||
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('User balance was successfully increased'),
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
events.$emit('toaster', {
|
||||
type: 'danger',
|
||||
message: this.$t('popup_error.title'),
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
this.isUpdatingBalanceAmount = false
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('User balance was successfully increased'),
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
events.$emit('toaster', {
|
||||
type: 'danger',
|
||||
message: this.$t('popup_error.title'),
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
this.isUpdatingBalanceAmount = false
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,77 +1,74 @@
|
||||
<template>
|
||||
<PageTab>
|
||||
<div class="card shadow-card">
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('user_box_password.title') }}
|
||||
</FormLabel>
|
||||
|
||||
<AppInputText :title="$t('Reset User Password')" :description="$t('user_box_password.description')" :is-last="true">
|
||||
<ButtonBase @click.native="requestPasswordResetEmail" :loading="isSendingRequest" :disabled="isSendingRequest" class="sm:w-auto w-full" button-style="theme">
|
||||
{{ $t('admin_page_user.send_password_link') }}
|
||||
</ButtonBase>
|
||||
</AppInputText>
|
||||
</div>
|
||||
<AppInputText :title="$t('Reset User Password')" :description="$t('user_box_password.description')" :is-last="true">
|
||||
<ButtonBase @click.native="requestPasswordResetEmail" :loading="isSendingRequest" :disabled="isSendingRequest" class="w-full sm:w-auto" button-style="theme">
|
||||
{{ $t('admin_page_user.send_password_link') }}
|
||||
</ButtonBase>
|
||||
</AppInputText>
|
||||
</div>
|
||||
</PageTab>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import PageTabGroup from "../../../../components/Others/Layout/PageTabGroup";
|
||||
import AppInputSwitch from "../../../../components/Admin/AppInputSwitch"
|
||||
import FormLabel from "../../../../components/Others/Forms/FormLabel";
|
||||
import ButtonBase from "../../../../components/FilesView/ButtonBase";
|
||||
import SetupBox from "../../../../components/Others/Forms/SetupBox";
|
||||
import PageTab from "../../../../components/Others/Layout/PageTab";
|
||||
import InfoBox from "../../../../components/Others/Forms/InfoBox";
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {events} from '../../../../bus'
|
||||
import axios from 'axios'
|
||||
import AppInputText from "../../../../components/Admin/AppInputText";
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import PageTabGroup from '../../../../components/Others/Layout/PageTabGroup'
|
||||
import AppInputSwitch from '../../../../components/Admin/AppInputSwitch'
|
||||
import FormLabel from '../../../../components/Others/Forms/FormLabel'
|
||||
import ButtonBase from '../../../../components/FilesView/ButtonBase'
|
||||
import SetupBox from '../../../../components/Others/Forms/SetupBox'
|
||||
import PageTab from '../../../../components/Others/Layout/PageTab'
|
||||
import InfoBox from '../../../../components/Others/Forms/InfoBox'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { events } from '../../../../bus'
|
||||
import axios from 'axios'
|
||||
import AppInputText from '../../../../components/Admin/AppInputText'
|
||||
|
||||
export default {
|
||||
name: 'UserPassword',
|
||||
components: {
|
||||
AppInputText,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AppInputSwitch,
|
||||
PageTabGroup,
|
||||
ButtonBase,
|
||||
FormLabel,
|
||||
SetupBox,
|
||||
required,
|
||||
InfoBox,
|
||||
PageTab,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
isSendingRequest: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
requestPasswordResetEmail() {
|
||||
|
||||
this.isSendingRequest = true
|
||||
|
||||
axios
|
||||
.post(`${this.$store.getters.api}/admin/users/${this.$route.params.id}/reset-password`,
|
||||
{}
|
||||
)
|
||||
.then(() => {
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.sended_password'),
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
events.$emit('alert:open', {
|
||||
title: this.$t('popup_error.title'),
|
||||
message: this.$t('popup_error.message'),
|
||||
})
|
||||
})
|
||||
.finally(() => this.isSendingRequest = false)
|
||||
}
|
||||
export default {
|
||||
name: 'UserPassword',
|
||||
components: {
|
||||
AppInputText,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AppInputSwitch,
|
||||
PageTabGroup,
|
||||
ButtonBase,
|
||||
FormLabel,
|
||||
SetupBox,
|
||||
required,
|
||||
InfoBox,
|
||||
PageTab,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
isSendingRequest: false,
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
requestPasswordResetEmail() {
|
||||
this.isSendingRequest = true
|
||||
|
||||
axios
|
||||
.post(`${this.$store.getters.api}/admin/users/${this.$route.params.id}/reset-password`, {})
|
||||
.then(() => {
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.sended_password'),
|
||||
})
|
||||
})
|
||||
.catch(() => {
|
||||
events.$emit('alert:open', {
|
||||
title: this.$t('popup_error.title'),
|
||||
message: this.$t('popup_error.message'),
|
||||
})
|
||||
})
|
||||
.finally(() => (this.isSendingRequest = false))
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,79 +1,80 @@
|
||||
<template>
|
||||
<PageTab :is-loading="isLoading" v-if="storage">
|
||||
|
||||
<!--Storage Usage-->
|
||||
<div v-if="distribution" class="card shadow-card">
|
||||
<FormLabel icon="hard-drive">
|
||||
<!--Storage Usage-->
|
||||
<div v-if="distribution" class="card shadow-card">
|
||||
<FormLabel icon="hard-drive">
|
||||
{{ $t('Storage Usage') }}
|
||||
</FormLabel>
|
||||
|
||||
<b class="sm:text-3xl text-2xl font-extrabold -mt-3 block mb-0.5">
|
||||
{{ storage.data.attributes.used }}
|
||||
</b>
|
||||
<b class="-mt-3 mb-0.5 block text-2xl font-extrabold sm:text-3xl">
|
||||
{{ storage.data.attributes.used }}
|
||||
</b>
|
||||
|
||||
<b v-if="['fixed', 'none'].includes(config.subscriptionType)" class="mt-0.5 block text-sm text-gray-400">
|
||||
{{ $t('Total of') }} {{ storage.data.attributes.capacity }} {{ $t('Used') }}
|
||||
</b>
|
||||
<b v-if="['fixed', 'none'].includes(config.subscriptionType)" class="mt-0.5 block text-sm text-gray-400">
|
||||
{{ $t('Total of') }} {{ storage.data.attributes.capacity }}
|
||||
{{ $t('Used') }}
|
||||
</b>
|
||||
|
||||
<ProgressLine v-if="storage.data.attributes.used !== '0B'" :data="distribution" class="mt-5" />
|
||||
</div>
|
||||
<ProgressLine v-if="storage.data.attributes.used !== '0B'" :data="distribution" class="mt-5" />
|
||||
</div>
|
||||
|
||||
<!--Upload-->
|
||||
<div v-if="distribution" class="card shadow-card">
|
||||
<FormLabel icon="hard-drive">
|
||||
<!--Upload-->
|
||||
<div v-if="distribution" class="card shadow-card">
|
||||
<FormLabel icon="hard-drive">
|
||||
{{ $t('Upload') }}
|
||||
</FormLabel>
|
||||
|
||||
<b class="sm:text-3xl text-2xl font-extrabold -mt-3 block mb-0.5">
|
||||
{{ storage.data.meta.traffic.upload }}
|
||||
</b>
|
||||
<b class="-mt-3 mb-0.5 block text-2xl font-extrabold sm:text-3xl">
|
||||
{{ storage.data.meta.traffic.upload }}
|
||||
</b>
|
||||
|
||||
<b class="mb-3 block text-sm text-gray-400 mb-5">
|
||||
{{ $t('In last 45 days') }}
|
||||
</b>
|
||||
<b class="mb-3 mb-5 block text-sm text-gray-400">
|
||||
{{ $t('In last 45 days') }}
|
||||
</b>
|
||||
|
||||
<BarChart :data="storage.data.meta.traffic.chart.upload" color="#FFBD2D" />
|
||||
</div>
|
||||
<BarChart :data="storage.data.meta.traffic.chart.upload" color="#FFBD2D" />
|
||||
</div>
|
||||
|
||||
<!--Download-->
|
||||
<div v-if="distribution" class="card shadow-card">
|
||||
<FormLabel icon="hard-drive">
|
||||
<!--Download-->
|
||||
<div v-if="distribution" class="card shadow-card">
|
||||
<FormLabel icon="hard-drive">
|
||||
{{ $t('Download') }}
|
||||
</FormLabel>
|
||||
|
||||
<b class="sm:text-3xl text-2xl font-extrabold -mt-3 block mb-0.5">
|
||||
{{ storage.data.meta.traffic.download }}
|
||||
</b>
|
||||
<b class="-mt-3 mb-0.5 block text-2xl font-extrabold sm:text-3xl">
|
||||
{{ storage.data.meta.traffic.download }}
|
||||
</b>
|
||||
|
||||
<b class="mb-3 block text-sm text-gray-400 mb-5">
|
||||
{{ $t('In last 45 days') }}
|
||||
</b>
|
||||
<b class="mb-3 mb-5 block text-sm text-gray-400">
|
||||
{{ $t('In last 45 days') }}
|
||||
</b>
|
||||
|
||||
<BarChart :data="storage.data.meta.traffic.chart.download" color="#9d66fe" />
|
||||
</div>
|
||||
<BarChart :data="storage.data.meta.traffic.chart.download" color="#9d66fe" />
|
||||
</div>
|
||||
|
||||
<!--Set Storage Size-->
|
||||
<div v-if="config.storageLimit && ! user.data.attributes.subscription && config.subscriptionType !== 'metered'" class="card shadow-card">
|
||||
<!--Set Storage Size-->
|
||||
<div v-if="config.storageLimit && !user.data.attributes.subscription && config.subscriptionType !== 'metered'" class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('user_box_storage.title') }}
|
||||
</FormLabel>
|
||||
<ValidationObserver ref="changeStorageCapacity" @submit.prevent="changeStorageCapacity" v-slot="{ invalid }" tag="form">
|
||||
<ValidationProvider tag="div" v-slot="{ errors }" mode="passive" name="Capacity" rules="required">
|
||||
<AppInputText :title="$t('admin_page_user.label_change_capacity')" :description="$t('user_box_storage.description')" :error="errors[0]" :is-last="true">
|
||||
<div class="sm:flex sm:space-x-4 sm:space-y-0 space-y-4">
|
||||
<input v-model="capacity"
|
||||
:placeholder="$t('admin_page_user.label_change_capacity')"
|
||||
type="number"
|
||||
min="1"
|
||||
max="999999999"
|
||||
class="focus-border-theme input-dark"
|
||||
:class="{'border-red': errors[0]}"
|
||||
/>
|
||||
<ButtonBase :loading="isSendingRequest" :disabled="isSendingRequest" type="submit" button-style="theme" class="sm:w-auto w-full">
|
||||
{{ $t('admin_page_user.change_capacity') }}
|
||||
</ButtonBase>
|
||||
</div>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('admin_page_user.label_change_capacity')" :description="$t('user_box_storage.description')" :error="errors[0]" :is-last="true">
|
||||
<div class="space-y-4 sm:flex sm:space-x-4 sm:space-y-0">
|
||||
<input
|
||||
v-model="capacity"
|
||||
:placeholder="$t('admin_page_user.label_change_capacity')"
|
||||
type="number"
|
||||
min="1"
|
||||
max="999999999"
|
||||
class="focus-border-theme input-dark"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
<ButtonBase :loading="isSendingRequest" :disabled="isSendingRequest" type="submit" button-style="theme" class="w-full sm:w-auto">
|
||||
{{ $t('admin_page_user.change_capacity') }}
|
||||
</ButtonBase>
|
||||
</div>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
@@ -81,119 +82,110 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ProgressLine from "../../../../components/Admin/ProgressLine";
|
||||
import AppInputText from "../../../../components/Admin/AppInputText";
|
||||
import FormLabel from "../../../../components/Others/Forms/FormLabel";
|
||||
import InfoBox from "../../../../components/Others/Forms/InfoBox";
|
||||
import PageTabGroup from "../../../../components/Others/Layout/PageTabGroup";
|
||||
import PageTab from "../../../../components/Others/Layout/PageTab";
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import ButtonBase from "../../../../components/FilesView/ButtonBase";
|
||||
import SetupBox from "../../../../components/Others/Forms/SetupBox";
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import BarChart from "../../../../components/UI/BarChart"
|
||||
import {events} from '../../../../bus'
|
||||
import {mapGetters} from "vuex"
|
||||
import axios from 'axios'
|
||||
import ProgressLine from '../../../../components/Admin/ProgressLine'
|
||||
import AppInputText from '../../../../components/Admin/AppInputText'
|
||||
import FormLabel from '../../../../components/Others/Forms/FormLabel'
|
||||
import InfoBox from '../../../../components/Others/Forms/InfoBox'
|
||||
import PageTabGroup from '../../../../components/Others/Layout/PageTabGroup'
|
||||
import PageTab from '../../../../components/Others/Layout/PageTab'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import ButtonBase from '../../../../components/FilesView/ButtonBase'
|
||||
import SetupBox from '../../../../components/Others/Forms/SetupBox'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import BarChart from '../../../../components/UI/BarChart'
|
||||
import { events } from '../../../../bus'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'UserStorage',
|
||||
props: [
|
||||
'user'
|
||||
],
|
||||
components: {
|
||||
ProgressLine,
|
||||
AppInputText,
|
||||
PageTabGroup,
|
||||
FormLabel,
|
||||
PageTab,
|
||||
InfoBox,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
ButtonBase,
|
||||
SetupBox,
|
||||
required,
|
||||
BarChart,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
isSendingRequest: false,
|
||||
capacity: undefined,
|
||||
storage: undefined,
|
||||
distribution: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async changeStorageCapacity() {
|
||||
export default {
|
||||
name: 'UserStorage',
|
||||
props: ['user'],
|
||||
components: {
|
||||
ProgressLine,
|
||||
AppInputText,
|
||||
PageTabGroup,
|
||||
FormLabel,
|
||||
PageTab,
|
||||
InfoBox,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
ButtonBase,
|
||||
SetupBox,
|
||||
required,
|
||||
BarChart,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
isSendingRequest: false,
|
||||
capacity: undefined,
|
||||
storage: undefined,
|
||||
distribution: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async changeStorageCapacity() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.changeStorageCapacity.validate()
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.changeStorageCapacity.validate();
|
||||
if (!isValid) return
|
||||
|
||||
if (!isValid) return;
|
||||
this.isSendingRequest = true
|
||||
|
||||
this.isSendingRequest = true
|
||||
// Send request to get user reset link
|
||||
axios
|
||||
.post(this.$store.getters.api + '/admin/users/' + this.$route.params.id + '/capacity', {
|
||||
attributes: {
|
||||
max_storage_amount: this.capacity,
|
||||
},
|
||||
_method: 'patch',
|
||||
})
|
||||
.then(() => {
|
||||
// Reset errors
|
||||
this.$refs.changeStorageCapacity.reset()
|
||||
|
||||
// Send request to get user reset link
|
||||
axios
|
||||
.post(this.$store.getters.api + '/admin/users/' + this.$route.params.id + '/capacity', {
|
||||
attributes: {
|
||||
max_storage_amount: this.capacity
|
||||
},
|
||||
_method: 'patch'
|
||||
this.isSendingRequest = false
|
||||
|
||||
this.getStorageDetails()
|
||||
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.changed_capacity'),
|
||||
})
|
||||
.then(() => {
|
||||
})
|
||||
.catch((error) => {
|
||||
this.isSendingRequest = false
|
||||
|
||||
// Reset errors
|
||||
this.$refs.changeStorageCapacity.reset()
|
||||
|
||||
this.isSendingRequest = false
|
||||
|
||||
this.getStorageDetails()
|
||||
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('toaster.changed_capacity'),
|
||||
})
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
this.isSendingRequest = false
|
||||
|
||||
if (error.response.status == 422) {
|
||||
|
||||
// Password validation error
|
||||
if (error.response.data.errors['attributes.max_storage_amount']) {
|
||||
|
||||
this.$refs.changeStorageCapacity.setErrors({
|
||||
'Capacity': this.$t('errors.capacity_digit')
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
||||
events.$emit('alert:open', {
|
||||
title: this.$t('popup_error.title'),
|
||||
message: this.$t('popup_error.message'),
|
||||
if (error.response.status == 422) {
|
||||
// Password validation error
|
||||
if (error.response.data.errors['attributes.max_storage_amount']) {
|
||||
this.$refs.changeStorageCapacity.setErrors({
|
||||
Capacity: this.$t('errors.capacity_digit'),
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
getStorageDetails() {
|
||||
axios.get('/api/admin/users/' + this.$route.params.id + '/storage')
|
||||
.then(response => {
|
||||
this.distribution = this.$mapStorageUsage(response.data)
|
||||
|
||||
this.storage = response.data
|
||||
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
} else {
|
||||
events.$emit('alert:open', {
|
||||
title: this.$t('popup_error.title'),
|
||||
message: this.$t('popup_error.message'),
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
created() {
|
||||
this.getStorageDetails()
|
||||
}
|
||||
}
|
||||
getStorageDetails() {
|
||||
axios.get('/api/admin/users/' + this.$route.params.id + '/storage').then((response) => {
|
||||
this.distribution = this.$mapStorageUsage(response.data)
|
||||
|
||||
this.storage = response.data
|
||||
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getStorageDetails()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,136 +1,121 @@
|
||||
<template>
|
||||
<PageTab :is-loading="isLoading">
|
||||
<UserMeteredSubscription v-if="subscription && config.subscriptionType === 'metered'" :subscription="subscription" :user="user" />
|
||||
|
||||
<UserMeteredSubscription
|
||||
v-if="subscription && config.subscriptionType === 'metered'"
|
||||
:subscription="subscription"
|
||||
:user="user"
|
||||
/>
|
||||
<UserFixedSubscription v-if="subscription && config.subscriptionType === 'fixed'" :subscription="subscription" :user="user" />
|
||||
|
||||
<UserFixedSubscription
|
||||
v-if="subscription && config.subscriptionType === 'fixed'"
|
||||
:subscription="subscription"
|
||||
:user="user"
|
||||
/>
|
||||
<!--Free Plan-->
|
||||
<div v-if="!subscription && config.subscriptionType === 'fixed'" class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Subscription') }}
|
||||
</FormLabel>
|
||||
|
||||
<!--Free Plan-->
|
||||
<div v-if="!subscription && config.subscriptionType === 'fixed'" class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Subscription') }}
|
||||
</FormLabel>
|
||||
<b class="-mt-3 mb-0.5 block text-2xl font-extrabold sm:text-3xl">
|
||||
{{ $t('Free Plan') }}
|
||||
</b>
|
||||
|
||||
<b class="sm:text-3xl text-2xl font-extrabold -mt-3 block mb-0.5">
|
||||
{{ $t('Free Plan') }}
|
||||
</b>
|
||||
<b class="block text-sm text-gray-400">
|
||||
{{ $t('1GB Free storage space with 5 Team members') }}
|
||||
</b>
|
||||
</div>
|
||||
|
||||
<b class="block text-sm text-gray-400">
|
||||
{{ $t('1GB Free storage space with 5 Team members') }}
|
||||
</b>
|
||||
</div>
|
||||
|
||||
<!--Transactions-->
|
||||
<div class="card shadow-card">
|
||||
<FormLabel icon="file-text">
|
||||
<!--Transactions-->
|
||||
<div class="card shadow-card">
|
||||
<FormLabel icon="file-text">
|
||||
{{ $t('Transactions') }}
|
||||
</FormLabel>
|
||||
|
||||
<DatatableWrapper
|
||||
class="overflow-x-auto"
|
||||
@init="isLoading = false"
|
||||
:api="'/api/admin/users/' + this.$route.params.id + '/transactions'"
|
||||
:paginator="true"
|
||||
:columns="columns"
|
||||
>
|
||||
<DatatableWrapper
|
||||
class="overflow-x-auto"
|
||||
@init="isLoading = false"
|
||||
:api="'/api/admin/users/' + this.$route.params.id + '/transactions'"
|
||||
:paginator="true"
|
||||
:columns="columns"
|
||||
>
|
||||
<template slot-scope="{ row }">
|
||||
|
||||
<!--Transaction rows-->
|
||||
<!--Transaction rows-->
|
||||
<MeteredTransactionRow v-if="config.subscriptionType === 'metered'" :row="row" @showDetail="showTransactionDetail" />
|
||||
<FixedTransactionRow v-if="config.subscriptionType === 'fixed'" :row="row" />
|
||||
|
||||
<!--Transaction detail-->
|
||||
<MeteredTransactionDetailRow v-if="row.data.attributes.metadata && showedTransactionDetailById === row.data.id" :row="row" />
|
||||
<FixedTransactionRow v-if="config.subscriptionType === 'fixed'" :row="row" />
|
||||
|
||||
<!--Transaction detail-->
|
||||
<MeteredTransactionDetailRow v-if="row.data.attributes.metadata && showedTransactionDetailById === row.data.id" :row="row" />
|
||||
</template>
|
||||
|
||||
<!--Empty page-->
|
||||
<!--Empty page-->
|
||||
<template v-slot:empty-page>
|
||||
<InfoBox style="margin-bottom: 0">
|
||||
<p>{{ $t("User doesn't have any transactions yet.") }}</p>
|
||||
<p>
|
||||
{{ $t("User doesn't have any transactions yet.") }}
|
||||
</p>
|
||||
</InfoBox>
|
||||
</template>
|
||||
</DatatableWrapper>
|
||||
</div>
|
||||
</div>
|
||||
</PageTab>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MeteredTransactionDetailRow from "../../../../components/Subscription/MeteredTransactionDetailRow"
|
||||
import MeteredTransactionRow from "../../../../components/Subscription/MeteredTransactionRow"
|
||||
import FixedTransactionRow from "../../../../components/Subscription/FixedTransactionRow"
|
||||
import DatatableWrapper from "../../../../components/Others/Tables/DatatableWrapper";
|
||||
import FormLabel from "../../../../components/Others/Forms/FormLabel"
|
||||
import PageTab from "../../../../components/Others/Layout/PageTab";
|
||||
import InfoBox from "../../../../components/Others/Forms/InfoBox";
|
||||
import UserMeteredSubscription from "./UserMeteredSubscription"
|
||||
import UserFixedSubscription from "./UserFixedSubscription"
|
||||
import {mapGetters} from "vuex"
|
||||
import axios from 'axios'
|
||||
import MeteredTransactionDetailRow from '../../../../components/Subscription/MeteredTransactionDetailRow'
|
||||
import MeteredTransactionRow from '../../../../components/Subscription/MeteredTransactionRow'
|
||||
import FixedTransactionRow from '../../../../components/Subscription/FixedTransactionRow'
|
||||
import DatatableWrapper from '../../../../components/Others/Tables/DatatableWrapper'
|
||||
import FormLabel from '../../../../components/Others/Forms/FormLabel'
|
||||
import PageTab from '../../../../components/Others/Layout/PageTab'
|
||||
import InfoBox from '../../../../components/Others/Forms/InfoBox'
|
||||
import UserMeteredSubscription from './UserMeteredSubscription'
|
||||
import UserFixedSubscription from './UserFixedSubscription'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'UserSubscription',
|
||||
props: [
|
||||
'user'
|
||||
],
|
||||
components: {
|
||||
MeteredTransactionDetailRow,
|
||||
UserMeteredSubscription,
|
||||
MeteredTransactionRow,
|
||||
UserFixedSubscription,
|
||||
FixedTransactionRow,
|
||||
DatatableWrapper,
|
||||
FormLabel,
|
||||
InfoBox,
|
||||
PageTab,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config',
|
||||
]),
|
||||
columns() {
|
||||
let filter = {
|
||||
metered: ['user_id'],
|
||||
fixed: ['type', 'user_id'],
|
||||
}
|
||||
export default {
|
||||
name: 'UserSubscription',
|
||||
props: ['user'],
|
||||
components: {
|
||||
MeteredTransactionDetailRow,
|
||||
UserMeteredSubscription,
|
||||
MeteredTransactionRow,
|
||||
UserFixedSubscription,
|
||||
FixedTransactionRow,
|
||||
DatatableWrapper,
|
||||
FormLabel,
|
||||
InfoBox,
|
||||
PageTab,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
columns() {
|
||||
let filter = {
|
||||
metered: ['user_id'],
|
||||
fixed: ['type', 'user_id'],
|
||||
}
|
||||
|
||||
return this.$store.getters.transactionColumns.filter(column => !filter[config.subscriptionType].includes(column.field))
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showedTransactionDetailById: undefined,
|
||||
subscription: undefined,
|
||||
isLoading: true,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showTransactionDetail(id) {
|
||||
if (this.showedTransactionDetailById === id)
|
||||
this.showedTransactionDetailById = undefined
|
||||
else
|
||||
this.showedTransactionDetailById = id
|
||||
}
|
||||
},
|
||||
created() {
|
||||
axios.get(`/api/subscriptions/admin/users/${this.$route.params.id}/subscription`)
|
||||
.then(response => {
|
||||
this.subscription = response.data.data
|
||||
return this.$store.getters.transactionColumns.filter((column) => !filter[config.subscriptionType].includes(column.field))
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showedTransactionDetailById: undefined,
|
||||
subscription: undefined,
|
||||
isLoading: true,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showTransactionDetail(id) {
|
||||
if (this.showedTransactionDetailById === id) this.showedTransactionDetailById = undefined
|
||||
else this.showedTransactionDetailById = id
|
||||
},
|
||||
},
|
||||
created() {
|
||||
axios
|
||||
.get(`/api/subscriptions/admin/users/${this.$route.params.id}/subscription`)
|
||||
.then((response) => {
|
||||
this.subscription = response.data.data
|
||||
|
||||
this.isLoading = false
|
||||
})
|
||||
.catch(error => {
|
||||
if (error.response.status === 404)
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
}
|
||||
this.isLoading = false
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response.status === 404) this.isLoading = false
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,53 +1,66 @@
|
||||
<template>
|
||||
<AuthContentWrapper ref="auth">
|
||||
|
||||
<!--Create new password-->
|
||||
<AuthContent name="create-new-password" :visible="true">
|
||||
<Headline
|
||||
:title="$t('page_create_password.title')"
|
||||
:description="$t('page_create_password.subtitle')"
|
||||
/>
|
||||
<Headline :title="$t('page_create_password.title')" :description="$t('page_create_password.subtitle')" />
|
||||
|
||||
<ValidationObserver @submit.prevent="createNewPassword" ref="create_new_password" v-slot="{ invalid }" tag="form" class="space-y-4 mb-12 text-left">
|
||||
|
||||
<div class="md:flex md:items-center mb-5 md:max-w-lg mx-auto">
|
||||
<label class="md:w-72 md:text-right md:pr-4 font-bold md:mb-0 mb-1.5 block">
|
||||
{{ $t('page_create_password.label_email') }}:
|
||||
</label>
|
||||
<ValidationObserver @submit.prevent="createNewPassword" ref="create_new_password" v-slot="{ invalid }" tag="form" class="mb-12 space-y-4 text-left">
|
||||
<div class="mx-auto mb-5 md:flex md:max-w-lg md:items-center">
|
||||
<label class="mb-1.5 block font-bold md:mb-0 md:w-72 md:pr-4 md:text-right"> {{ $t('page_create_password.label_email') }}: </label>
|
||||
<ValidationProvider tag="div" mode="passive" class="w-full text-left" name="E-Mail" rules="required" v-slot="{ errors }">
|
||||
<input v-model="recoverPassword.email" :placeholder="$t('page_login.placeholder_email')" type="email" class="font-bold px-5 py-3.5 dark:bg-2x-dark-foreground bg-light-background w-full rounded-lg focus-border-theme appearance-none border border-transparent" :class="{'border-red': errors[0]}"/>
|
||||
<input
|
||||
v-model="recoverPassword.email"
|
||||
:placeholder="$t('page_login.placeholder_email')"
|
||||
type="email"
|
||||
class="focus-border-theme w-full appearance-none rounded-lg border border-transparent bg-light-background px-5 py-3.5 font-bold dark:bg-2x-dark-foreground"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="md:flex md:items-center mb-5 md:max-w-lg mx-auto">
|
||||
<label class="md:w-72 md:text-right md:pr-4 font-bold md:mb-0 mb-1.5 block">
|
||||
{{ $t('page_create_password.label_new_pass') }}:
|
||||
</label>
|
||||
<div class="mx-auto mb-5 md:flex md:max-w-lg md:items-center">
|
||||
<label class="mb-1.5 block font-bold md:mb-0 md:w-72 md:pr-4 md:text-right"> {{ $t('page_create_password.label_new_pass') }}: </label>
|
||||
<ValidationProvider tag="div" mode="passive" class="w-full text-left" name="New Password" rules="required" v-slot="{ errors }">
|
||||
<input v-model="recoverPassword.newPassword" :placeholder="$t('page_create_password.label_new_pass')" type="password" class="font-bold px-5 py-3.5 dark:bg-2x-dark-foreground bg-light-background w-full rounded-lg focus-border-theme appearance-none border border-transparent" :class="{'border-red': errors[0]}"/>
|
||||
<input
|
||||
v-model="recoverPassword.newPassword"
|
||||
:placeholder="$t('page_create_password.label_new_pass')"
|
||||
type="password"
|
||||
class="focus-border-theme w-full appearance-none rounded-lg border border-transparent bg-light-background px-5 py-3.5 font-bold dark:bg-2x-dark-foreground"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="md:flex md:items-center mb-5 md:max-w-lg mx-auto">
|
||||
<label class="md:w-72 md:text-right md:pr-4 font-bold md:mb-0 mb-1.5 block">
|
||||
{{ $t('page_create_password.label_confirm_pass') }}:
|
||||
</label>
|
||||
<div class="mx-auto mb-5 md:flex md:max-w-lg md:items-center">
|
||||
<label class="mb-1.5 block font-bold md:mb-0 md:w-72 md:pr-4 md:text-right"> {{ $t('page_create_password.label_confirm_pass') }}: </label>
|
||||
<ValidationProvider tag="div" mode="passive" class="w-full text-left" name="Confirm Password" rules="required" v-slot="{ errors }">
|
||||
<input v-model="recoverPassword.newPasswordConfirm" :placeholder="$t('page_create_password.label_confirm_pass')" type="password" class="font-bold px-5 py-3.5 dark:bg-2x-dark-foreground bg-light-background w-full rounded-lg focus-border-theme appearance-none border border-transparent" :class="{'border-red': errors[0]}"/>
|
||||
<input
|
||||
v-model="recoverPassword.newPasswordConfirm"
|
||||
:placeholder="$t('page_create_password.label_confirm_pass')"
|
||||
type="password"
|
||||
class="focus-border-theme w-full appearance-none rounded-lg border border-transparent bg-light-background px-5 py-3.5 font-bold dark:bg-2x-dark-foreground"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<AuthButton class="md:w-min w-full justify-center mt-12" icon="chevron-right" :text="$t('page_create_password.button_update')" :loading="isLoading" :disabled="isLoading"/>
|
||||
</div>
|
||||
<div>
|
||||
<AuthButton
|
||||
class="mt-12 w-full justify-center md:w-min"
|
||||
icon="chevron-right"
|
||||
:text="$t('page_create_password.button_update')"
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
/>
|
||||
</div>
|
||||
</ValidationObserver>
|
||||
|
||||
<span class="block">
|
||||
{{ $t('page_forgotten_password.password_remember_text') }}
|
||||
<router-link :to="{name: 'SignIn'}" class="font-bold text-theme">
|
||||
{{ $t('page_forgotten_password.password_remember_text') }}
|
||||
<router-link :to="{ name: 'SignIn' }" class="text-theme font-bold">
|
||||
{{ $t('page_forgotten_password.password_remember_button') }}
|
||||
</router-link>
|
||||
</span>
|
||||
@@ -55,122 +68,112 @@
|
||||
|
||||
<!--Password reset successfully-->
|
||||
<AuthContent name="password-reset-successfully" :visible="false">
|
||||
<img v-if="config.app_logo" class="logo mx-auto" :src="$getImage(config.app_logo)" :alt="config.app_name">
|
||||
<b v-if="! config.app_logo" class="auth-logo-text">{{ config.app_name }}</b>
|
||||
<img v-if="config.app_logo" class="logo mx-auto" :src="$getImage(config.app_logo)" :alt="config.app_name" />
|
||||
<b v-if="!config.app_logo" class="auth-logo-text">{{ config.app_name }}</b>
|
||||
|
||||
<h1>{{ $t('page_forgotten_password.pass_reseted_title') }}</h1>
|
||||
<h2>{{ $t('page_forgotten_password.pass_reseted_subtitle') }}</h2>
|
||||
|
||||
<router-link :to="{name: 'SignIn'}">
|
||||
<AuthButton icon="chevron-right" :text="$t('page_forgotten_password.pass_reseted_signin')"/>
|
||||
<router-link :to="{ name: 'SignIn' }">
|
||||
<AuthButton icon="chevron-right" :text="$t('page_forgotten_password.pass_reseted_signin')" />
|
||||
</router-link>
|
||||
</AuthContent>
|
||||
</AuthContentWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AuthContentWrapper from "../../components/Auth/AuthContentWrapper";
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContent from "../../components/Auth/AuthContent";
|
||||
import AuthButton from "../../components/Auth/AuthButton";
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import Headline from "./Headline";
|
||||
import {mapGetters} from 'vuex'
|
||||
import axios from 'axios'
|
||||
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContent from '../../components/Auth/AuthContent'
|
||||
import AuthButton from '../../components/Auth/AuthButton'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import Headline from './Headline'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'CreateNewPassword',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
Headline,
|
||||
required,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
recoverPassword: {
|
||||
token: undefined,
|
||||
email: '',
|
||||
newPassword: '',
|
||||
newPasswordConfirm: '',
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goToAuthPage(slug) {
|
||||
|
||||
this.$refs.auth.$children.forEach(page => {
|
||||
|
||||
// Hide current step
|
||||
page.isVisible = false
|
||||
|
||||
if (page.$props.name === slug) {
|
||||
|
||||
// Go to next step
|
||||
page.isVisible = true
|
||||
}
|
||||
})
|
||||
export default {
|
||||
name: 'CreateNewPassword',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
Headline,
|
||||
required,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
recoverPassword: {
|
||||
token: undefined,
|
||||
email: '',
|
||||
newPassword: '',
|
||||
newPasswordConfirm: '',
|
||||
},
|
||||
async createNewPassword() {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goToAuthPage(slug) {
|
||||
this.$refs.auth.$children.forEach((page) => {
|
||||
// Hide current step
|
||||
page.isVisible = false
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.create_new_password.validate();
|
||||
if (page.$props.name === slug) {
|
||||
// Go to next step
|
||||
page.isVisible = true
|
||||
}
|
||||
})
|
||||
},
|
||||
async createNewPassword() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.create_new_password.validate()
|
||||
|
||||
if (!isValid) return;
|
||||
if (!isValid) return
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Send request to get user reset link
|
||||
axios
|
||||
.post(this.$store.getters.api + '/password/reset', {
|
||||
email: this.recoverPassword.email,
|
||||
token: this.recoverPassword.token,
|
||||
password: this.recoverPassword.newPassword,
|
||||
password_confirmation: this.recoverPassword.newPasswordConfirm,
|
||||
})
|
||||
.then(() => {
|
||||
// Send request to get user reset link
|
||||
axios
|
||||
.post(this.$store.getters.api + '/password/reset', {
|
||||
email: this.recoverPassword.email,
|
||||
token: this.recoverPassword.token,
|
||||
password: this.recoverPassword.newPassword,
|
||||
password_confirmation: this.recoverPassword.newPasswordConfirm,
|
||||
})
|
||||
.then(() => {
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
this.goToAuthPage('password-reset-successfully')
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
if (error.response.status === 422) {
|
||||
|
||||
if (error.response.data.error) {
|
||||
|
||||
this.$refs.create_new_password.setErrors({
|
||||
'E-Mail': error.response.data.error
|
||||
});
|
||||
}
|
||||
|
||||
if (error.response.data.errors['password']) {
|
||||
|
||||
this.$refs.create_new_password.setErrors({
|
||||
'New Password': error.response.data.errors['password']
|
||||
});
|
||||
}
|
||||
this.goToAuthPage('password-reset-successfully')
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response.status === 422) {
|
||||
if (error.response.data.error) {
|
||||
this.$refs.create_new_password.setErrors({
|
||||
'E-Mail': error.response.data.error,
|
||||
})
|
||||
}
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (error.response.data.errors['password']) {
|
||||
this.$refs.create_new_password.setErrors({
|
||||
'New Password': error.response.data.errors['password'],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Get token
|
||||
this.recoverPassword.token = this.$route.query.token
|
||||
}
|
||||
}
|
||||
</script>
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// Get token
|
||||
this.recoverPassword.token = this.$route.query.token
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,25 +1,39 @@
|
||||
<template>
|
||||
<AuthContentWrapper ref="auth" class="h-screen">
|
||||
|
||||
<!--Forgotten your password?-->
|
||||
<AuthContent name="forgotten-password" :visible="true">
|
||||
<Headline
|
||||
:title="$t('page_forgotten_password.title')"
|
||||
:description="$t('page_forgotten_password.subtitle')"
|
||||
/>
|
||||
<Headline :title="$t('page_forgotten_password.title')" :description="$t('page_forgotten_password.subtitle')" />
|
||||
|
||||
<ValidationObserver @submit.prevent="forgottenPassword" ref="forgotten_password" v-slot="{ invalid }" tag="form" class="md:flex items-start md:space-x-4 md:space-y-0 space-y-4 mb-12">
|
||||
<ValidationProvider tag="div" mode="passive" class="w-full text-left relative" name="E-Mail" rules="required" v-slot="{ errors }">
|
||||
<input v-model="recoverEmail" :placeholder="$t('page_login.placeholder_email')" type="email" class="font-bold px-5 py-3.5 dark:bg-2x-dark-foreground bg-light-background w-full rounded-lg focus-border-theme appearance-none border border-transparent" :class="{'border-red': errors[0]}"/>
|
||||
<span class="text-red-600 text-xs text-left" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
<ValidationObserver
|
||||
@submit.prevent="forgottenPassword"
|
||||
ref="forgotten_password"
|
||||
v-slot="{ invalid }"
|
||||
tag="form"
|
||||
class="mb-12 items-start space-y-4 md:flex md:space-x-4 md:space-y-0"
|
||||
>
|
||||
<ValidationProvider tag="div" mode="passive" class="relative w-full text-left" name="E-Mail" rules="required" v-slot="{ errors }">
|
||||
<input
|
||||
v-model="recoverEmail"
|
||||
:placeholder="$t('page_login.placeholder_email')"
|
||||
type="email"
|
||||
class="focus-border-theme w-full appearance-none rounded-lg border border-transparent bg-light-background px-5 py-3.5 font-bold dark:bg-2x-dark-foreground"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
|
||||
<AuthButton class="md:w-min w-full justify-center" icon="chevron-right" :text="$t('page_forgotten_password.button_get_link')" :loading="isLoading" :disabled="isLoading"/>
|
||||
<AuthButton
|
||||
class="w-full justify-center md:w-min"
|
||||
icon="chevron-right"
|
||||
:text="$t('page_forgotten_password.button_get_link')"
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
/>
|
||||
</ValidationObserver>
|
||||
|
||||
<span class="block">
|
||||
{{ $t('page_forgotten_password.password_remember_text') }}
|
||||
<router-link :to="{name: 'SignIn'}" class="font-bold text-theme">
|
||||
{{ $t('page_forgotten_password.password_remember_text') }}
|
||||
<router-link :to="{ name: 'SignIn' }" class="text-theme font-bold">
|
||||
{{ $t('page_forgotten_password.password_remember_button') }}
|
||||
</router-link>
|
||||
</span>
|
||||
@@ -27,14 +41,11 @@
|
||||
|
||||
<!--Password reset link send-->
|
||||
<AuthContent name="password-reset-link-sended" :visible="false">
|
||||
<Headline
|
||||
:title="$t('page_forgotten_password.pass_sennded_title')"
|
||||
:description="$t('page_forgotten_password.pass_sennded_subtitle')"
|
||||
/>
|
||||
<Headline :title="$t('page_forgotten_password.pass_sennded_title')" :description="$t('page_forgotten_password.pass_sennded_subtitle')" />
|
||||
|
||||
<span class="block">
|
||||
{{ $t('page_forgotten_password.password_remember_text') }}
|
||||
<router-link :to="{name: 'SignIn'}" class="font-bold text-theme">
|
||||
{{ $t('page_forgotten_password.password_remember_text') }}
|
||||
<router-link :to="{ name: 'SignIn' }" class="text-theme font-bold">
|
||||
{{ $t('page_forgotten_password.password_remember_button') }}
|
||||
</router-link>
|
||||
</span>
|
||||
@@ -43,78 +54,73 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from "../../components/Auth/AuthContentWrapper";
|
||||
import AuthContent from "../../components/Auth/AuthContent";
|
||||
import AuthButton from "../../components/Auth/AuthButton";
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import Headline from "./Headline";
|
||||
import {mapGetters} from 'vuex'
|
||||
import axios from 'axios'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
|
||||
import AuthContent from '../../components/Auth/AuthContent'
|
||||
import AuthButton from '../../components/Auth/AuthButton'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import Headline from './Headline'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'ForgottenPassword',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
required,
|
||||
Headline,
|
||||
export default {
|
||||
name: 'ForgottenPassword',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
required,
|
||||
Headline,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
recoverEmail: '',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goToAuthPage(slug) {
|
||||
this.$refs.auth.$children.forEach((page) => {
|
||||
// Hide current step
|
||||
page.isVisible = false
|
||||
|
||||
if (page.$props.name === slug) {
|
||||
// Go to next step
|
||||
page.isVisible = true
|
||||
}
|
||||
})
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config',
|
||||
]),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
recoverEmail: '',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goToAuthPage(slug) {
|
||||
this.$refs.auth.$children.forEach(page => {
|
||||
async forgottenPassword() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.forgotten_password.validate()
|
||||
|
||||
// Hide current step
|
||||
page.isVisible = false
|
||||
if (!isValid) return
|
||||
|
||||
if (page.$props.name === slug) {
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Go to next step
|
||||
page.isVisible = true
|
||||
// Send request to get user reset link
|
||||
axios
|
||||
.post('/api/password/email', {
|
||||
email: this.recoverEmail,
|
||||
})
|
||||
.then(() => {
|
||||
this.goToAuthPage('password-reset-link-sended')
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response.status === 422) {
|
||||
this.$refs.forgotten_password.setErrors({
|
||||
'E-Mail': error.response.data.message,
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
async forgottenPassword() {
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.forgotten_password.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Send request to get user reset link
|
||||
axios
|
||||
.post('/api/password/email', {
|
||||
email: this.recoverEmail
|
||||
})
|
||||
.then(() => {
|
||||
|
||||
this.goToAuthPage('password-reset-link-sended')
|
||||
}).catch(error => {
|
||||
|
||||
if (error.response.status === 422) {
|
||||
this.$refs.forgotten_password.setErrors({
|
||||
'E-Mail': error.response.data.message
|
||||
});
|
||||
}
|
||||
}).finally(() => this.isLoading = false)
|
||||
},
|
||||
}
|
||||
}
|
||||
.finally(() => (this.isLoading = false))
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,42 +1,36 @@
|
||||
<template>
|
||||
<div class="mb-14">
|
||||
<!--Custom content-->
|
||||
<slot></slot>
|
||||
<div class="mb-14">
|
||||
<!--Custom content-->
|
||||
<slot></slot>
|
||||
|
||||
<!--Default application logo-->
|
||||
<div v-if="! $slots.default">
|
||||
<!--Default application logo-->
|
||||
<div v-if="!$slots.default">
|
||||
<!--Image logo-->
|
||||
<img v-if="config.app_logo" class="mx-auto mb-6 w-28 md:w-32" :src="$getImage(config.app_logo)" :alt="config.app_name" />
|
||||
|
||||
<!--Image logo-->
|
||||
<img v-if="config.app_logo" class="md:w-32 w-28 mb-6 mx-auto" :src="$getImage(config.app_logo)" :alt="config.app_name">
|
||||
<!--Text logo if image isn't available-->
|
||||
<b v-if="!config.app_logo" class="mb-10 block text-xl font-bold">
|
||||
{{ config.app_name }}
|
||||
</b>
|
||||
</div>
|
||||
|
||||
<!--Text logo if image isn't available-->
|
||||
<b v-if="! config.app_logo" class="font-bold text-xl mb-10 block">
|
||||
{{ config.app_name }}
|
||||
</b>
|
||||
</div>
|
||||
<h1 class="mb-0.5 text-3xl font-extrabold md:text-4xl">
|
||||
{{ title }}
|
||||
</h1>
|
||||
|
||||
<h1 class="md:text-4xl text-3xl font-extrabold mb-0.5">
|
||||
{{ title }}
|
||||
</h1>
|
||||
|
||||
<h2 class="md:text-2xl text-xl font-normal">
|
||||
{{ description }}
|
||||
</h2>
|
||||
</div>
|
||||
<h2 class="text-xl font-normal md:text-2xl">
|
||||
{{ description }}
|
||||
</h2>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {mapGetters} from "vuex";
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Headline',
|
||||
props: [
|
||||
'description',
|
||||
'title',
|
||||
],
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config',
|
||||
])
|
||||
}
|
||||
}
|
||||
</script>
|
||||
export default {
|
||||
name: 'Headline',
|
||||
props: ['description', 'title'],
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,130 +1,137 @@
|
||||
<template>
|
||||
<AuthContentWrapper ref="auth" class="h-screen">
|
||||
|
||||
<!--Log In by Email-->
|
||||
<AuthContent name="log-in" :visible="true">
|
||||
<Headline
|
||||
:title="$t('page_login.title')"
|
||||
:description="$t('page_login.subtitle')"
|
||||
/>
|
||||
<Headline :title="$t('page_login.title')" :description="$t('page_login.subtitle')" />
|
||||
|
||||
<ValidationObserver @submit.prevent="logIn" ref="log_in" v-slot="{ invalid }" tag="form" class="md:flex items-start md:space-x-4 md:space-y-0 space-y-4 mb-12">
|
||||
<ValidationObserver @submit.prevent="logIn" ref="log_in" v-slot="{ invalid }" tag="form" class="mb-12 items-start space-y-4 md:flex md:space-x-4 md:space-y-0">
|
||||
<ValidationProvider class="w-full text-left" tag="div" mode="passive" name="E-Mail" rules="required" v-slot="{ errors }">
|
||||
<input class="font-bold px-5 py-3.5 dark:bg-2x-dark-foreground bg-light-background w-full rounded-lg focus-border-theme appearance-none border border-transparent" :class="{'border-red': errors[0]}" v-model="loginEmail" :placeholder="$t('page_login.placeholder_email')" type="email" />
|
||||
<span class="text-red-600 text-xs text-left" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
<input
|
||||
class="focus-border-theme w-full appearance-none rounded-lg border border-transparent bg-light-background px-5 py-3.5 font-bold dark:bg-2x-dark-foreground"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
v-model="loginEmail"
|
||||
:placeholder="$t('page_login.placeholder_email')"
|
||||
type="email"
|
||||
/>
|
||||
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
|
||||
<AuthButton class="md:w-min w-full justify-center" icon="chevron-right" :text="$t('page_login.button_next')" :loading="isLoading" :disabled="isLoading" />
|
||||
<AuthButton class="w-full justify-center md:w-min" icon="chevron-right" :text="$t('page_login.button_next')" :loading="isLoading" :disabled="isLoading" />
|
||||
</ValidationObserver>
|
||||
|
||||
<SocialiteAuthenticationButtons />
|
||||
|
||||
<span v-if="config.userRegistration" class="block">
|
||||
{{ $t('page_login.registration_text') }}
|
||||
<router-link class="font-bold text-theme" :to="{name: 'SignUp'}">
|
||||
<router-link class="text-theme font-bold" :to="{ name: 'SignUp' }">
|
||||
{{ $t('page_login.registration_button') }}
|
||||
</router-link>
|
||||
</span>
|
||||
</AuthContent>
|
||||
|
||||
<!--Log in By Password-->
|
||||
<!--Log in By Password-->
|
||||
<AuthContent name="sign-in" :visible="false">
|
||||
<Headline
|
||||
v-if="checkedAccount"
|
||||
:title="$t('page_sign_in.title', {name: checkedAccount.name})"
|
||||
:description="$t('page_sign_in.subtitle')"
|
||||
>
|
||||
<img class="user-avatar mx-auto rounded-xl w-28 mb-6 shadow-xl" :src="checkedAccount.avatar.md" :alt="checkedAccount.name">
|
||||
</Headline>
|
||||
<Headline v-if="checkedAccount" :title="$t('page_sign_in.title', { name: checkedAccount.name })" :description="$t('page_sign_in.subtitle')">
|
||||
<img class="user-avatar mx-auto mb-6 w-28 rounded-xl shadow-xl" :src="checkedAccount.avatar.md" :alt="checkedAccount.name" />
|
||||
</Headline>
|
||||
|
||||
<ValidationObserver @submit.prevent="singIn" ref="sign_in" v-slot="{ invalid }" tag="form" class="md:flex items-start md:space-x-4 md:space-y-0 space-y-4 mb-12">
|
||||
<ValidationObserver @submit.prevent="singIn" ref="sign_in" v-slot="{ invalid }" tag="form" class="mb-12 items-start space-y-4 md:flex md:space-x-4 md:space-y-0">
|
||||
<ValidationProvider tag="div" mode="passive" class="w-full text-left" name="User Password" rules="required" v-slot="{ errors }">
|
||||
<input v-model="loginPassword" :placeholder="$t('page_sign_in.placeholder_password')" type="password" class="font-bold px-5 py-3.5 dark:bg-2x-dark-foreground bg-light-background w-full h-full rounded-lg focus-border-theme appearance-none border border-transparent" :class="{'border-red': errors[0]}" />
|
||||
<span class="text-red-600 text-xs text-left" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
<input
|
||||
v-model="loginPassword"
|
||||
:placeholder="$t('page_sign_in.placeholder_password')"
|
||||
type="password"
|
||||
class="focus-border-theme h-full w-full appearance-none rounded-lg border border-transparent bg-light-background px-5 py-3.5 font-bold dark:bg-2x-dark-foreground"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
|
||||
<AuthButton class="md:w-min w-full justify-center" icon="chevron-right" :text="$t('page_sign_in.button_log_in')" :loading="isLoading" :disabled="isLoading" />
|
||||
<AuthButton class="w-full justify-center md:w-min" icon="chevron-right" :text="$t('page_sign_in.button_log_in')" :loading="isLoading" :disabled="isLoading" />
|
||||
</ValidationObserver>
|
||||
|
||||
<span class="block">
|
||||
{{ $t('page_sign_in.password_reset_text') }}
|
||||
<router-link :to="{name: 'ForgottenPassword'}" class="font-bold text-theme">
|
||||
{{ $t('page_sign_in.password_reset_text') }}
|
||||
<router-link :to="{ name: 'ForgottenPassword' }" class="text-theme font-bold">
|
||||
{{ $t('page_sign_in.password_reset_button') }}
|
||||
</router-link>
|
||||
</span>
|
||||
</AuthContent>
|
||||
|
||||
<!--Resend verification email-->
|
||||
<!--Resend verification email-->
|
||||
<AuthContent name="not-verified" :visible="false">
|
||||
<Headline
|
||||
v-if="checkedAccount"
|
||||
:title="$t('page_sign_in_2fa_title', {name: checkedAccount.name})"
|
||||
:description="$t('page_not_verified.subtitle')"
|
||||
>
|
||||
<img class="user-avatar mx-auto rounded-xl w-28 mb-6 shadow-xl" :src="checkedAccount.avatar.md" :alt="checkedAccount.name">
|
||||
</Headline>
|
||||
<Headline v-if="checkedAccount" :title="$t('page_sign_in_2fa_title', { name: checkedAccount.name })" :description="$t('page_not_verified.subtitle')">
|
||||
<img class="user-avatar mx-auto mb-6 w-28 rounded-xl shadow-xl" :src="checkedAccount.avatar.md" :alt="checkedAccount.name" />
|
||||
</Headline>
|
||||
|
||||
<span class="block">
|
||||
{{ $t('page_not_verified.resend_text') }}
|
||||
{{ $t('page_not_verified.resend_text') }}
|
||||
<b @click="resendEmail" class="text-theme cursor-pointer">
|
||||
{{ $t('page_not_verified.resend_button') }}
|
||||
</b>
|
||||
{{ $t('page_not_verified.resend_button') }}
|
||||
</b>
|
||||
</span>
|
||||
</AuthContent>
|
||||
|
||||
<!-- Log in by 2fa -->
|
||||
<!-- Log in by 2fa -->
|
||||
<AuthContent name="two-factor-authentication" :visible="false">
|
||||
<Headline
|
||||
v-if="checkedAccount"
|
||||
:title="$t('page_sign_in_2fa_title', {name: checkedAccount.name})"
|
||||
:description="$t('page_sign_in_2fa_subtitle')"
|
||||
>
|
||||
<img class="user-avatar mx-auto rounded-xl w-28 mb-6 shadow-xl" :src="checkedAccount.avatar.md" :alt="checkedAccount.name">
|
||||
</Headline>
|
||||
<Headline v-if="checkedAccount" :title="$t('page_sign_in_2fa_title', { name: checkedAccount.name })" :description="$t('page_sign_in_2fa_subtitle')">
|
||||
<img class="user-avatar mx-auto mb-6 w-28 rounded-xl shadow-xl" :src="checkedAccount.avatar.md" :alt="checkedAccount.name" />
|
||||
</Headline>
|
||||
|
||||
<ValidationObserver ref="two_factor_authentication" v-slot="{ invalid }" tag="form" class="mb-12">
|
||||
<ValidationProvider tag="div" mode="passive" class="mx-auto" name="Two Factor Authentication" rules="required" v-slot="{ errors }">
|
||||
<input v-model="twoFactorCode" ref="twoFactorCodeInput" :placeholder="$t('page_sign_in.placeholder_2fa')" @input="twoFactorChallenge(false)" type="text" maxlength="6" class="font-bold px-5 py-3.5 dark:bg-2x-dark-foreground bg-light-background text-center md:w-80 w-full h-full rounded-lg focus-border-theme appearance-none border border-transparent" :class="{'border-red': errors[0]}" />
|
||||
<span class="text-red-600 text-xs mt-2 text-center block" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
<input
|
||||
v-model="twoFactorCode"
|
||||
ref="twoFactorCodeInput"
|
||||
:placeholder="$t('page_sign_in.placeholder_2fa')"
|
||||
@input="twoFactorChallenge(false)"
|
||||
type="text"
|
||||
maxlength="6"
|
||||
class="focus-border-theme h-full w-full appearance-none rounded-lg border border-transparent bg-light-background px-5 py-3.5 text-center font-bold dark:bg-2x-dark-foreground md:w-80"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
<span class="mt-2 block text-center text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</ValidationObserver>
|
||||
|
||||
<span class="block">
|
||||
{{ $t('page_sign_in.2fa_recovery_text') }}
|
||||
<span class="block">
|
||||
{{ $t('page_sign_in.2fa_recovery_text') }}
|
||||
<b @click="goToAuthPage('two-factor-recovery')" class="text-theme cursor-pointer cursor-pointer">
|
||||
{{ $t('page_sign_in.2fa_recovery_button') }}
|
||||
{{ $t('page_sign_in.2fa_recovery_button') }}
|
||||
</b>
|
||||
</span>
|
||||
|
||||
<div class="relative h-12 mt-10 w-full">
|
||||
<div class="relative mt-10 h-12 w-full">
|
||||
<Spinner v-if="isLoading" class="spinner" />
|
||||
</div>
|
||||
|
||||
</AuthContent>
|
||||
|
||||
<!-- Log in by 2fa with recovery code -->
|
||||
<!-- Log in by 2fa with recovery code -->
|
||||
<AuthContent name="two-factor-recovery" :visible="false">
|
||||
<Headline
|
||||
v-if="checkedAccount"
|
||||
:title="$t('page_sign_in_2fa_title', {name: checkedAccount.name})"
|
||||
:description="$t('page_sign_in.2fa_recovery_subtitle')"
|
||||
>
|
||||
<img class="user-avatar mx-auto rounded-xl w-28 mb-6 shadow-xl" :src="checkedAccount.avatar.md" :alt="checkedAccount.name">
|
||||
</Headline>
|
||||
<Headline v-if="checkedAccount" :title="$t('page_sign_in_2fa_title', { name: checkedAccount.name })" :description="$t('page_sign_in.2fa_recovery_subtitle')">
|
||||
<img class="user-avatar mx-auto mb-6 w-28 rounded-xl shadow-xl" :src="checkedAccount.avatar.md" :alt="checkedAccount.name" />
|
||||
</Headline>
|
||||
|
||||
<ValidationObserver ref="two_factor_recovery" v-slot="{ invalid }" tag="form" class="mb-12">
|
||||
<ValidationProvider tag="div" mode="passive" class="mx-auto" name="Two Factor Recovery" rules="required" v-slot="{ errors }">
|
||||
<input v-model="twoFactorRecoveryCode" :placeholder="$t('page_sign_in.placeholder_2fa_recovery')" @input="twoFactorChallenge(true)" type="text" maxlength="21" class="font-bold px-5 py-3.5 dark:bg-2x-dark-foreground bg-light-background text-center md:w-80 w-full h-full rounded-lg focus-border-theme appearance-none border border-transparent" :class="{'border-red': errors[0]}" />
|
||||
<span class="text-red-600 text-xs mt-2 text-center block" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
<input
|
||||
v-model="twoFactorRecoveryCode"
|
||||
:placeholder="$t('page_sign_in.placeholder_2fa_recovery')"
|
||||
@input="twoFactorChallenge(true)"
|
||||
type="text"
|
||||
maxlength="21"
|
||||
class="focus-border-theme h-full w-full appearance-none rounded-lg border border-transparent bg-light-background px-5 py-3.5 text-center font-bold dark:bg-2x-dark-foreground md:w-80"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
<span class="mt-2 block text-center text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
|
||||
</ValidationObserver>
|
||||
|
||||
<b @click="goToAuthPage('two-factor-authentication')" class="text-theme block cursor-pointer">
|
||||
{{ $t('2fa.i_have_2fa_app') }}
|
||||
</b>
|
||||
<b @click="goToAuthPage('two-factor-authentication')" class="text-theme block cursor-pointer">
|
||||
{{ $t('2fa.i_have_2fa_app') }}
|
||||
</b>
|
||||
|
||||
<div v-if="isLoading" class="relative h-12 mt-10 w-full">
|
||||
<div v-if="isLoading" class="relative mt-10 h-12 w-full">
|
||||
<Spinner class="spinner" />
|
||||
</div>
|
||||
</AuthContent>
|
||||
@@ -132,248 +139,222 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AuthContentWrapper from "../../components/Auth/AuthContentWrapper";
|
||||
import {ValidationObserver, ValidationProvider} from 'vee-validate/dist/vee-validate.full'
|
||||
import SocialiteAuthenticationButtons from "../../components/Auth/SocialiteAuthenticationButtons";
|
||||
import AuthContent from "../../components/Auth/AuthContent";
|
||||
import AuthButton from "../../components/Auth/AuthButton";
|
||||
import Spinner from "../../components/FilesView/Spinner";
|
||||
import {mapGetters} from 'vuex'
|
||||
import {events} from '../../bus'
|
||||
import axios from 'axios'
|
||||
import Headline from "./Headline";
|
||||
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
|
||||
import { ValidationObserver, ValidationProvider } from 'vee-validate/dist/vee-validate.full'
|
||||
import SocialiteAuthenticationButtons from '../../components/Auth/SocialiteAuthenticationButtons'
|
||||
import AuthContent from '../../components/Auth/AuthContent'
|
||||
import AuthButton from '../../components/Auth/AuthButton'
|
||||
import Spinner from '../../components/FilesView/Spinner'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { events } from '../../bus'
|
||||
import axios from 'axios'
|
||||
import Headline from './Headline'
|
||||
|
||||
export default {
|
||||
name: 'SignIn',
|
||||
components: {
|
||||
SocialiteAuthenticationButtons,
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
Headline,
|
||||
Spinner,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config'
|
||||
]),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
validSignIn: false,
|
||||
checkedAccount: undefined,
|
||||
loginPassword: '',
|
||||
loginEmail: '',
|
||||
twoFactorCode: '',
|
||||
twoFactorRecoveryCode: '',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goToAuthPage(slug) {
|
||||
export default {
|
||||
name: 'SignIn',
|
||||
components: {
|
||||
SocialiteAuthenticationButtons,
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
Headline,
|
||||
Spinner,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
validSignIn: false,
|
||||
checkedAccount: undefined,
|
||||
loginPassword: '',
|
||||
loginEmail: '',
|
||||
twoFactorCode: '',
|
||||
twoFactorRecoveryCode: '',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goToAuthPage(slug) {
|
||||
this.$refs.auth.$children.forEach((page) => {
|
||||
// Hide current step
|
||||
page.isVisible = page.$props.name === slug
|
||||
})
|
||||
},
|
||||
resendEmail() {
|
||||
axios
|
||||
.post('/api/user/email/verify/resend', {
|
||||
email: this.loginEmail,
|
||||
})
|
||||
.then(() => {
|
||||
this.$router.push({ name: 'SuccessfullySend' })
|
||||
})
|
||||
.catch(() => {
|
||||
this.$isSomethingWrong()
|
||||
})
|
||||
},
|
||||
async logIn() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.log_in.validate()
|
||||
|
||||
this.$refs.auth.$children.forEach(page => {
|
||||
if (!isValid) return
|
||||
|
||||
// Hide current step
|
||||
page.isVisible = page.$props.name === slug;
|
||||
})
|
||||
},
|
||||
resendEmail() {
|
||||
axios.post('/api/user/email/verify/resend', {
|
||||
email: this.loginEmail
|
||||
})
|
||||
.then(() => {
|
||||
this.$router.push({name: 'SuccessfullySend'})
|
||||
})
|
||||
.catch(() => {
|
||||
this.$isSomethingWrong()
|
||||
})
|
||||
},
|
||||
async logIn() {
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.log_in.validate();
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/user/check', {
|
||||
email: this.loginEmail,
|
||||
})
|
||||
.then((response) => {
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
if (!isValid) return;
|
||||
this.checkedAccount = response.data
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
if (response.data.oauth_provider) {
|
||||
// Redirect user to socialite login if he's accout is registered by socialite
|
||||
this.$store.dispatch('socialiteRedirect', response.data.oauth_provider)
|
||||
} else {
|
||||
// Show sign in password page
|
||||
this.goToAuthPage('sign-in')
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response.status == 404) {
|
||||
this.$refs.log_in.setErrors({
|
||||
'E-Mail': [error.response.data],
|
||||
})
|
||||
}
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/user/check', {
|
||||
email: this.loginEmail,
|
||||
})
|
||||
.then(response => {
|
||||
if (error.response.status == 500) {
|
||||
events.$emit('alert:open', {
|
||||
emoji: '🤔',
|
||||
title: this.$t('popup_signup_error.title'),
|
||||
message: this.$t('popup_signup_error.message'),
|
||||
})
|
||||
}
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
async singIn() {
|
||||
// Validate fields
|
||||
const isValid = this.validSignIn ? this.validSignIn : await this.$refs.sign_in.validate()
|
||||
|
||||
this.checkedAccount = response.data
|
||||
if (!isValid) return
|
||||
|
||||
if (response.data.oauth_provider) {
|
||||
// Redirect user to socialite login if he's accout is registered by socialite
|
||||
this.$store.dispatch('socialiteRedirect', response.data.oauth_provider)
|
||||
if (!this.checkedAccount.verified) {
|
||||
this.goToAuthPage('not-verified')
|
||||
|
||||
} else {
|
||||
// Show sign in password page
|
||||
this.goToAuthPage('sign-in')
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
if (error.response.status == 404) {
|
||||
// Send request to get user token
|
||||
axios
|
||||
.post('/login', {
|
||||
email: this.loginEmail,
|
||||
password: this.loginPassword,
|
||||
})
|
||||
.then((response) => {
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
this.$refs.log_in.setErrors({
|
||||
'E-Mail': [error.response.data]
|
||||
});
|
||||
}
|
||||
// If is enabled two factor authentication
|
||||
if (response.data.two_factor && !this.validSignIn) {
|
||||
this.validSignIn = true
|
||||
|
||||
if (error.response.status == 500) {
|
||||
this.goToAuthPage('two-factor-authentication')
|
||||
|
||||
events.$emit('alert:open', {
|
||||
emoji: '🤔',
|
||||
title: this.$t('popup_signup_error.title'),
|
||||
message: this.$t('popup_signup_error.message')
|
||||
})
|
||||
}
|
||||
// Autofocus to input
|
||||
this.$nextTick(() => this.$refs.twoFactorCodeInput.focus())
|
||||
}
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
async singIn() {
|
||||
// If is disabled two factor authentication
|
||||
if (!response.data.two_factor) {
|
||||
// Set login state
|
||||
this.$store.commit('SET_AUTHORIZED', true)
|
||||
|
||||
// Validate fields
|
||||
const isValid = this.validSignIn ? this.validSignIn : await this.$refs.sign_in.validate();
|
||||
// Go to files page
|
||||
this.proceedToAccount()
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response.status == 422) {
|
||||
this.$refs.sign_in.setErrors({
|
||||
'User Password': [this.$t('validation_errors.incorrect_password')],
|
||||
})
|
||||
}
|
||||
|
||||
if (!isValid) return;
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
async twoFactorChallenge(recovery) {
|
||||
// Check if is normal authentication or recovery
|
||||
if ((!recovery && this.twoFactorCode.length === 6) || (recovery && this.twoFactorRecoveryCode.length === 21)) {
|
||||
this.isLoading = true
|
||||
|
||||
if (!this.checkedAccount.verified) {
|
||||
let payload = recovery ? { recovery_code: this.twoFactorRecoveryCode } : { code: this.twoFactorCode }
|
||||
|
||||
this.goToAuthPage('not-verified')
|
||||
axios
|
||||
.post('/two-factor-challenge', payload)
|
||||
.then(() => {
|
||||
this.isLoading = false
|
||||
|
||||
return
|
||||
}
|
||||
// Set login state
|
||||
this.$store.commit('SET_AUTHORIZED', true)
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
// Go to files page
|
||||
this.proceedToAccount()
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response.status == 422) {
|
||||
//Authentication bad input
|
||||
if (!recovery) {
|
||||
this.$refs.two_factor_authentication.setErrors({
|
||||
'Two Factor Authentication': this.$t('validation_errors.incorrect_2fa_code'),
|
||||
})
|
||||
}
|
||||
|
||||
// Send request to get user token
|
||||
axios
|
||||
.post('/login', {
|
||||
email: this.loginEmail,
|
||||
password: this.loginPassword,
|
||||
})
|
||||
.then((response) => {
|
||||
// Recovery bad input
|
||||
if (recovery) {
|
||||
this.$refs.two_factor_recovery.setErrors({
|
||||
'Two Factor Recovery': this.$t('validation_errors.incorrect_2fa_recovery_code'),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
// Repeat the login for next try to type right 2fa code / recovery code
|
||||
this.singIn()
|
||||
|
||||
// If is enabled two factor authentication
|
||||
if (response.data.two_factor && !this.validSignIn) {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
proceedToAccount() {
|
||||
if (this.$route.query.redirect) {
|
||||
this.$router.push(this.$route.query.redirect)
|
||||
} else {
|
||||
this.$router.push({ name: 'Files' })
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
this.$store.commit('PROCESSING_POPUP', undefined)
|
||||
|
||||
this.validSignIn = true
|
||||
|
||||
this.goToAuthPage('two-factor-authentication')
|
||||
|
||||
// Autofocus to input
|
||||
this.$nextTick(() => this.$refs.twoFactorCodeInput.focus())
|
||||
}
|
||||
|
||||
// If is disabled two factor authentication
|
||||
if (!response.data.two_factor) {
|
||||
|
||||
// Set login state
|
||||
this.$store.commit('SET_AUTHORIZED', true)
|
||||
|
||||
// Go to files page
|
||||
this.proceedToAccount()
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
if (error.response.status == 422) {
|
||||
|
||||
this.$refs.sign_in.setErrors({
|
||||
'User Password': [this.$t('validation_errors.incorrect_password')]
|
||||
});
|
||||
}
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
async twoFactorChallenge(recovery) {
|
||||
// Check if is normal authentication or recovery
|
||||
if (!recovery && this.twoFactorCode.length === 6 || recovery && this.twoFactorRecoveryCode.length === 21) {
|
||||
|
||||
this.isLoading = true
|
||||
|
||||
let payload = recovery
|
||||
? {recovery_code: this.twoFactorRecoveryCode}
|
||||
: {code: this.twoFactorCode}
|
||||
|
||||
axios.post('/two-factor-challenge', payload)
|
||||
.then(() => {
|
||||
|
||||
this.isLoading = false
|
||||
|
||||
// Set login state
|
||||
this.$store.commit('SET_AUTHORIZED', true)
|
||||
|
||||
// Go to files page
|
||||
this.proceedToAccount()
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
if (error.response.status == 422) {
|
||||
|
||||
//Authentication bad input
|
||||
if (!recovery) {
|
||||
|
||||
this.$refs.two_factor_authentication.setErrors({
|
||||
'Two Factor Authentication': this.$t('validation_errors.incorrect_2fa_code')
|
||||
})
|
||||
}
|
||||
|
||||
// Recovery bad input
|
||||
if (recovery) {
|
||||
|
||||
this.$refs.two_factor_recovery.setErrors({
|
||||
'Two Factor Recovery': this.$t('validation_errors.incorrect_2fa_recovery_code')
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Repeat the login for next try to type right 2fa code / recovery code
|
||||
this.singIn()
|
||||
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
|
||||
},
|
||||
proceedToAccount() {
|
||||
if (this.$route.query.redirect) {
|
||||
this.$router.push(this.$route.query.redirect)
|
||||
} else {
|
||||
this.$router.push({name: 'Files'})
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
this.$store.commit('PROCESSING_POPUP', undefined)
|
||||
|
||||
if (this.config.isDemo || this.config.isDev) {
|
||||
this.loginEmail = 'howdy@hi5ve.digital'
|
||||
this.loginPassword = 'vuefilemanager'
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.config.isDemo || this.config.isDev) {
|
||||
this.loginEmail = 'howdy@hi5ve.digital'
|
||||
this.loginPassword = 'vuefilemanager'
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,72 +1,104 @@
|
||||
<template>
|
||||
<AuthContentWrapper ref="auth">
|
||||
|
||||
<!--Registration-->
|
||||
<AuthContent name="sign-up" :visible="true" class="mt-4 mb-12">
|
||||
<Headline
|
||||
:title="$t('page_registration.title')"
|
||||
:description="$t('page_registration.subtitle')"
|
||||
/>
|
||||
<Headline :title="$t('page_registration.title')" :description="$t('page_registration.subtitle')" />
|
||||
|
||||
<ValidationObserver @submit.prevent="signUp" ref="sign_up" v-slot="{ invalid }" tag="form" class="space-y-4 mb-12 text-left">
|
||||
<ValidationObserver @submit.prevent="signUp" ref="sign_up" v-slot="{ invalid }" tag="form" class="mb-12 space-y-4 text-left">
|
||||
<div class="mx-auto mb-5 md:flex md:max-w-lg md:items-center">
|
||||
<label class="mb-1.5 block font-bold md:mb-0 md:w-72 md:pr-4 md:text-right"> {{ $t('page_registration.label_email') }}: </label>
|
||||
<ValidationProvider tag="div" mode="passive" class="w-full text-left" name="E-Mail" rules="required" v-slot="{ errors }">
|
||||
<input
|
||||
v-model="register.email"
|
||||
:placeholder="$t('page_registration.placeholder_email')"
|
||||
type="email"
|
||||
class="focus-border-theme w-full appearance-none rounded-lg border border-transparent bg-light-background px-5 py-3.5 font-bold dark:bg-2x-dark-foreground"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="md:flex md:items-center mb-5 md:max-w-lg mx-auto">
|
||||
<label class="md:w-72 md:text-right md:pr-4 font-bold md:mb-0 mb-1.5 block">
|
||||
{{ $t('page_registration.label_email') }}:
|
||||
</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="w-full text-left" name="E-Mail" rules="required" v-slot="{ errors }">
|
||||
<input v-model="register.email" :placeholder="$t('page_registration.placeholder_email')" type="email" class="font-bold px-5 py-3.5 dark:bg-2x-dark-foreground bg-light-background w-full rounded-lg focus-border-theme appearance-none border border-transparent" :class="{'border-red': errors[0]}"/>
|
||||
<span class="text-red-600 text-xs text-left" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<div class="mx-auto mb-5 md:flex md:max-w-lg md:items-center">
|
||||
<label class="mb-1.5 block font-bold md:mb-0 md:w-72 md:pr-4 md:text-right"> {{ $t('page_registration.label_name') }}: </label>
|
||||
<ValidationProvider tag="div" mode="passive" class="w-full text-left" name="Full Name" rules="required" v-slot="{ errors }">
|
||||
<input
|
||||
v-model="register.name"
|
||||
:placeholder="$t('page_registration.placeholder_name')"
|
||||
type="text"
|
||||
class="focus-border-theme w-full appearance-none rounded-lg border border-transparent bg-light-background px-5 py-3.5 font-bold dark:bg-2x-dark-foreground"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="md:flex md:items-center mb-5 md:max-w-lg mx-auto">
|
||||
<label class="md:w-72 md:text-right md:pr-4 font-bold md:mb-0 mb-1.5 block">
|
||||
{{ $t('page_registration.label_name') }}:
|
||||
</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="w-full text-left" name="Full Name" rules="required" v-slot="{ errors }">
|
||||
<input v-model="register.name" :placeholder="$t('page_registration.placeholder_name')" type="text" class="font-bold px-5 py-3.5 dark:bg-2x-dark-foreground bg-light-background w-full rounded-lg focus-border-theme appearance-none border border-transparent" :class="{'border-red': errors[0]}"/>
|
||||
<span class="text-red-600 text-xs text-left" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<div class="mx-auto mb-5 md:flex md:max-w-lg md:items-center">
|
||||
<label class="mb-1.5 block font-bold md:mb-0 md:w-72 md:pr-4 md:text-right"> {{ $t('page_registration.label_pass') }}: </label>
|
||||
<ValidationProvider tag="div" mode="passive" class="w-full text-left" name="Your New Password" rules="required" v-slot="{ errors }">
|
||||
<input
|
||||
v-model="register.password"
|
||||
:placeholder="$t('page_registration.placeholder_pass')"
|
||||
type="password"
|
||||
class="focus-border-theme w-full appearance-none rounded-lg border border-transparent bg-light-background px-5 py-3.5 font-bold dark:bg-2x-dark-foreground"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="md:flex md:items-center mb-5 md:max-w-lg mx-auto">
|
||||
<label class="md:w-72 md:text-right md:pr-4 font-bold md:mb-0 mb-1.5 block">
|
||||
{{ $t('page_registration.label_pass') }}:
|
||||
</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="w-full text-left" name="Your New Password" rules="required" v-slot="{ errors }">
|
||||
<input v-model="register.password" :placeholder="$t('page_registration.placeholder_pass')" type="password" class="font-bold px-5 py-3.5 dark:bg-2x-dark-foreground bg-light-background w-full rounded-lg focus-border-theme appearance-none border border-transparent" :class="{'border-red': errors[0]}"/>
|
||||
<span class="text-red-600 text-xs text-left" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="md:flex md:items-center mb-5 md:max-w-lg mx-auto">
|
||||
<label class="md:w-72 md:text-right md:pr-4 font-bold md:mb-0 mb-1.5 block">
|
||||
{{ $t('page_registration.label_confirm_pass') }}:
|
||||
</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="w-full text-left" name="Confirm Your Password" rules="required" v-slot="{ errors }">
|
||||
<input v-model="register.password_confirmation" :placeholder="$t('page_registration.placeholder_confirm_pass')" class="font-bold px-5 py-3.5 dark:bg-2x-dark-foreground bg-light-background w-full rounded-lg focus-border-theme appearance-none border border-transparent" type="password" :class="{'border-red': errors[0]}"/>
|
||||
<span class="text-red-600 text-xs text-left" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<div class="mx-auto mb-5 md:flex md:max-w-lg md:items-center">
|
||||
<label class="mb-1.5 block font-bold md:mb-0 md:w-72 md:pr-4 md:text-right"> {{ $t('page_registration.label_confirm_pass') }}: </label>
|
||||
<ValidationProvider tag="div" mode="passive" class="w-full text-left" name="Confirm Your Password" rules="required" v-slot="{ errors }">
|
||||
<input
|
||||
v-model="register.password_confirmation"
|
||||
:placeholder="$t('page_registration.placeholder_confirm_pass')"
|
||||
class="focus-border-theme w-full appearance-none rounded-lg border border-transparent bg-light-background px-5 py-3.5 font-bold dark:bg-2x-dark-foreground"
|
||||
type="password"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="text-center">
|
||||
<i18n path="page_registration.agreement" tag="p" class="mx-auto mt-12 mb-6 w-96 font-bold">
|
||||
<router-link :to="{name: 'DynamicPage', params: {slug: 'terms-of-service'}}" target="_blank" class="text-theme">
|
||||
{{ termsOfService.title }}
|
||||
</router-link>
|
||||
<router-link :to="{name: 'DynamicPage', params: {slug: 'privacy-policy'}}" target="_blank" class="text-theme">
|
||||
{{ privacyPolicy.title }}
|
||||
</router-link>
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'DynamicPage',
|
||||
params: { slug: 'terms-of-service' },
|
||||
}"
|
||||
target="_blank"
|
||||
class="text-theme"
|
||||
>
|
||||
{{ termsOfService.title }}
|
||||
</router-link>
|
||||
<router-link
|
||||
:to="{
|
||||
name: 'DynamicPage',
|
||||
params: { slug: 'privacy-policy' },
|
||||
}"
|
||||
target="_blank"
|
||||
class="text-theme"
|
||||
>
|
||||
{{ privacyPolicy.title }}
|
||||
</router-link>
|
||||
</i18n>
|
||||
<AuthButton class="md:w-min w-full justify-center" icon="chevron-right" :text="$t('page_registration.button_create_account')" :loading="isLoading" :disabled="isLoading"/>
|
||||
<AuthButton
|
||||
class="w-full justify-center md:w-min"
|
||||
icon="chevron-right"
|
||||
:text="$t('page_registration.button_create_account')"
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
/>
|
||||
</div>
|
||||
</ValidationObserver>
|
||||
|
||||
<SocialiteAuthenticationButtons/>
|
||||
<SocialiteAuthenticationButtons />
|
||||
|
||||
<span class="block">{{ $t('page_registration.have_an_account') }}
|
||||
<router-link :to="{name: 'SignIn'}" class="font-bold text-theme">
|
||||
<span class="block"
|
||||
>{{ $t('page_registration.have_an_account') }}
|
||||
<router-link :to="{ name: 'SignIn' }" class="text-theme font-bold">
|
||||
{{ $t('page_forgotten_password.password_remember_button') }}
|
||||
</router-link>
|
||||
</span>
|
||||
@@ -75,129 +107,119 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Headline from "./Headline";
|
||||
import AuthContentWrapper from "../../components/Auth/AuthContentWrapper";
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContent from "../../components/Auth/AuthContent";
|
||||
import AuthButton from "../../components/Auth/AuthButton";
|
||||
import SocialiteAuthenticationButtons from "../../components/Auth/SocialiteAuthenticationButtons";
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {mapGetters} from 'vuex'
|
||||
import {events} from '../../bus'
|
||||
import axios from 'axios'
|
||||
import Headline from './Headline'
|
||||
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContent from '../../components/Auth/AuthContent'
|
||||
import AuthButton from '../../components/Auth/AuthButton'
|
||||
import SocialiteAuthenticationButtons from '../../components/Auth/SocialiteAuthenticationButtons'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { events } from '../../bus'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'SignUp',
|
||||
components: {
|
||||
SocialiteAuthenticationButtons,
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
Headline,
|
||||
required,
|
||||
export default {
|
||||
name: 'SignUp',
|
||||
components: {
|
||||
SocialiteAuthenticationButtons,
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
Headline,
|
||||
required,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
privacyPolicy() {
|
||||
return this.config.legal.find((legal) => {
|
||||
return legal.slug === 'privacy-policy'
|
||||
})
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config'
|
||||
]),
|
||||
privacyPolicy() {
|
||||
return this.config.legal.find(legal => {
|
||||
return legal.slug === 'privacy-policy'
|
||||
})
|
||||
},
|
||||
termsOfService() {
|
||||
return this.config.legal.find(legal => {
|
||||
return legal.slug === 'terms-of-service'
|
||||
})
|
||||
},
|
||||
termsOfService() {
|
||||
return this.config.legal.find((legal) => {
|
||||
return legal.slug === 'terms-of-service'
|
||||
})
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
register: {
|
||||
name: '',
|
||||
email: '',
|
||||
password: '',
|
||||
password_confirmation: '',
|
||||
reCaptcha:null,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
register: {
|
||||
name: '',
|
||||
email: '',
|
||||
password: '',
|
||||
password_confirmation: '',
|
||||
reCaptcha: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async signUp() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.sign_up.validate()
|
||||
|
||||
if (!isValid) return
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Get ReCaptcha token
|
||||
if (config.allowedRecaptcha) {
|
||||
this.register.reCaptcha = await this.$reCaptchaToken('register').then((response) => {
|
||||
return response
|
||||
})
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async signUp() {
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.sign_up.validate();
|
||||
// Send request to get user token
|
||||
axios
|
||||
.post('/api/register', this.register)
|
||||
.then(() => {
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
if (!isValid) return;
|
||||
if (!this.config.userVerification) {
|
||||
// Set login state
|
||||
this.$store.commit('SET_AUTHORIZED', true)
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
// Go to files page
|
||||
this.$router.push({ name: 'Files' })
|
||||
} else {
|
||||
// Go to SuccessfullySend page
|
||||
this.$router.push({ name: 'SuccessfullySend' })
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response.status == 500) {
|
||||
events.$emit('alert:open', {
|
||||
emoji: '🤔',
|
||||
title: this.$t('popup_signup_error.title'),
|
||||
message: this.$t('popup_signup_error.message'),
|
||||
})
|
||||
}
|
||||
|
||||
// Get ReCaptcha token
|
||||
if(config.allowedRecaptcha) {
|
||||
this.register.reCaptcha = await this.$reCaptchaToken('register').then((response) => {
|
||||
return response
|
||||
})
|
||||
}
|
||||
|
||||
// Send request to get user token
|
||||
axios
|
||||
.post('/api/register', this.register)
|
||||
.then(() => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
if(! this.config.userVerification) {
|
||||
// Set login state
|
||||
this.$store.commit('SET_AUTHORIZED', true)
|
||||
|
||||
// Go to files page
|
||||
this.$router.push({name: 'Files'})
|
||||
} else {
|
||||
// Go to SuccessfullySend page
|
||||
this.$router.push({name: 'SuccessfullySend'})
|
||||
}
|
||||
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
if (error.response.status == 500) {
|
||||
|
||||
events.$emit('alert:open', {
|
||||
emoji: '🤔',
|
||||
title: this.$t('popup_signup_error.title'),
|
||||
message: this.$t('popup_signup_error.message')
|
||||
if (error.response.status == 422) {
|
||||
if (error.response.data.errors['email']) {
|
||||
this.$refs.sign_up.setErrors({
|
||||
'E-Mail': error.response.data.errors['email'],
|
||||
})
|
||||
}
|
||||
|
||||
if (error.response.status == 422) {
|
||||
|
||||
if (error.response.data.errors['email']) {
|
||||
|
||||
this.$refs.sign_up.setErrors({
|
||||
'E-Mail': error.response.data.errors['email']
|
||||
});
|
||||
}
|
||||
|
||||
if (error.response.data.errors['password']) {
|
||||
|
||||
this.$refs.sign_up.setErrors({
|
||||
'Your New Password': error.response.data.errors['password']
|
||||
});
|
||||
}
|
||||
if (error.response.data.errors['password']) {
|
||||
this.$refs.sign_up.setErrors({
|
||||
'Your New Password': error.response.data.errors['password'],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,38 +1,37 @@
|
||||
<template>
|
||||
<Spinner/>
|
||||
<Spinner />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Spinner from "../../components/FilesView/Spinner";
|
||||
import {events} from "../../bus";
|
||||
import Spinner from '../../components/FilesView/Spinner'
|
||||
import { events } from '../../bus'
|
||||
|
||||
export default {
|
||||
name: 'SocialiteCallback',
|
||||
components: {
|
||||
Spinner
|
||||
},
|
||||
created () {
|
||||
Spinner,
|
||||
},
|
||||
created() {
|
||||
axios
|
||||
.get(`/api${this.$route.fullPath}`)
|
||||
.then(() => {
|
||||
|
||||
// Set login state
|
||||
this.$store.commit('SET_AUTHORIZED', true)
|
||||
|
||||
// Go to files page
|
||||
this.$router.push({name: 'Files'})
|
||||
this.$router.push({ name: 'Files' })
|
||||
})
|
||||
.catch(error => {
|
||||
if (error.response.status === 401) {
|
||||
events.$emit('alert:open', {
|
||||
title: error.response.data.message,
|
||||
})
|
||||
} else {
|
||||
this.$isSomethingWrong()
|
||||
}
|
||||
.catch((error) => {
|
||||
if (error.response.status === 401) {
|
||||
events.$emit('alert:open', {
|
||||
title: error.response.data.message,
|
||||
})
|
||||
} else {
|
||||
this.$isSomethingWrong()
|
||||
}
|
||||
|
||||
this.$router.push({name: 'SignIn'})
|
||||
})
|
||||
}
|
||||
this.$router.push({ name: 'SignIn' })
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,31 +1,28 @@
|
||||
<template>
|
||||
<AuthContentWrapper class="h-screen">
|
||||
<AuthContent :visible="true">
|
||||
<Headline
|
||||
:title="$t('page_email_successfully_verified.title')"
|
||||
:description="$t('page_email_successfully_verified.subtitle')"
|
||||
/>
|
||||
|
||||
<router-link :to="{name: 'SignIn'}">
|
||||
<AuthButton icon="chevron-right" :text="$t('page_sign_in.button_log_in')"/>
|
||||
<Headline :title="$t('page_email_successfully_verified.title')" :description="$t('page_email_successfully_verified.subtitle')" />
|
||||
|
||||
<router-link :to="{ name: 'SignIn' }">
|
||||
<AuthButton icon="chevron-right" :text="$t('page_sign_in.button_log_in')" />
|
||||
</router-link>
|
||||
</AuthContent>
|
||||
</AuthContentWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AuthContentWrapper from "../../components/Auth/AuthContentWrapper";
|
||||
import AuthContent from "../../components/Auth/AuthContent";
|
||||
import AuthButton from "../../components/Auth/AuthButton";
|
||||
import Headline from "./Headline";
|
||||
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
|
||||
import AuthContent from '../../components/Auth/AuthContent'
|
||||
import AuthButton from '../../components/Auth/AuthButton'
|
||||
import Headline from './Headline'
|
||||
|
||||
export default {
|
||||
name: 'SuccessfullyEmailVerified',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
Headline,
|
||||
},
|
||||
}
|
||||
export default {
|
||||
name: 'SuccessfullyEmailVerified',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
Headline,
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
<template>
|
||||
<AuthContentWrapper class="h-screen">
|
||||
<AuthContent :visible="true">
|
||||
<Headline
|
||||
:title="$t('page_email_successfully_send.title')"
|
||||
:description="$t('page_email_successfully_send.subtitle')"
|
||||
/>
|
||||
<Headline :title="$t('page_email_successfully_send.title')" :description="$t('page_email_successfully_send.subtitle')" />
|
||||
|
||||
<span class="block">
|
||||
<router-link :to="{name: 'Homepage'}" class="font-bold text-theme">
|
||||
<span class="block">
|
||||
<router-link :to="{ name: 'Homepage' }" class="text-theme font-bold">
|
||||
{{ $t('go_home') }}
|
||||
</router-link>
|
||||
</span>
|
||||
@@ -16,18 +13,18 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AuthContentWrapper from "../../components/Auth/AuthContentWrapper";
|
||||
import AuthContent from "../../components/Auth/AuthContent";
|
||||
import AuthButton from "../../components/Auth/AuthButton";
|
||||
import Headline from "./Headline"
|
||||
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
|
||||
import AuthContent from '../../components/Auth/AuthContent'
|
||||
import AuthButton from '../../components/Auth/AuthButton'
|
||||
import Headline from './Headline'
|
||||
|
||||
export default {
|
||||
name: 'SuccessfullySendEmail',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
Headline,
|
||||
},
|
||||
}
|
||||
export default {
|
||||
name: 'SuccessfullySendEmail',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
Headline,
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,183 +1,172 @@
|
||||
<template>
|
||||
<ContentSidebar v-if="navigationTree && navigationTree.length >= 1">
|
||||
<!--Locations-->
|
||||
<ContentGroup :title="$t('sidebar.locations_title')">
|
||||
<div class="menu-list-wrapper vertical">
|
||||
<a class="menu-list-item link" @click="goHome">
|
||||
<div class="icon">
|
||||
<home-icon size="17"/>
|
||||
</div>
|
||||
<div class="label">
|
||||
{{ $t('Home') }}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</ContentGroup>
|
||||
<ContentSidebar v-if="navigationTree && navigationTree.length >= 1">
|
||||
<!--Locations-->
|
||||
<ContentGroup :title="$t('sidebar.locations_title')">
|
||||
<div class="menu-list-wrapper vertical">
|
||||
<a class="menu-list-item link" @click="goHome">
|
||||
<div class="icon">
|
||||
<home-icon size="17" />
|
||||
</div>
|
||||
<div class="label">
|
||||
{{ $t('Home') }}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</ContentGroup>
|
||||
|
||||
<!--Navigator-->
|
||||
<ContentGroup :title="$t('sidebar.navigator_title')" class="navigator">
|
||||
<TreeMenuNavigator class="folder-tree" :depth="0" :nodes="folder" v-for="folder in navigationTree" :key="folder.id" />
|
||||
</ContentGroup>
|
||||
</ContentSidebar>
|
||||
<!--Navigator-->
|
||||
<ContentGroup :title="$t('sidebar.navigator_title')" class="navigator">
|
||||
<TreeMenuNavigator class="folder-tree" :depth="0" :nodes="folder" v-for="folder in navigationTree" :key="folder.id" />
|
||||
</ContentGroup>
|
||||
</ContentSidebar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {FolderIcon, HomeIcon, LinkIcon, Trash2Icon, UploadCloudIcon, UserCheckIcon, UsersIcon, XIcon} from "vue-feather-icons";
|
||||
import TreeMenuNavigator from "../../../components/Others/TreeMenuNavigator";
|
||||
import ContentSidebar from "../../../components/Sidebar/ContentSidebar";
|
||||
import ContentGroup from "../../../components/Sidebar/ContentGroup";
|
||||
import {events} from "../../../bus";
|
||||
import {mapGetters} from "vuex";
|
||||
import { FolderIcon, HomeIcon, LinkIcon, Trash2Icon, UploadCloudIcon, UserCheckIcon, UsersIcon, XIcon } from 'vue-feather-icons'
|
||||
import TreeMenuNavigator from '../../../components/Others/TreeMenuNavigator'
|
||||
import ContentSidebar from '../../../components/Sidebar/ContentSidebar'
|
||||
import ContentGroup from '../../../components/Sidebar/ContentGroup'
|
||||
import { events } from '../../../bus'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: "NavigationSharePanel",
|
||||
components: {
|
||||
TreeMenuNavigator,
|
||||
ContentSidebar,
|
||||
ContentGroup,
|
||||
UploadCloudIcon,
|
||||
UserCheckIcon,
|
||||
FolderIcon,
|
||||
Trash2Icon,
|
||||
UsersIcon,
|
||||
HomeIcon,
|
||||
LinkIcon,
|
||||
XIcon,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'sharedDetail',
|
||||
'navigation',
|
||||
'clipboard',
|
||||
'config',
|
||||
'user',
|
||||
]),
|
||||
favourites() {
|
||||
return this.user.data.relationships.favourites.data.attributes.folders
|
||||
},
|
||||
storage() {
|
||||
return this.$store.getters.user.data.attributes.storage
|
||||
},
|
||||
tree() {
|
||||
return this.user.data.attributes.folders
|
||||
},
|
||||
navigationTree() {
|
||||
return this.navigation ? this.navigation[0].folders : undefined
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
draggedItem: undefined,
|
||||
area: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goHome() {
|
||||
this.$router.replace({
|
||||
name: 'Public',
|
||||
params: {
|
||||
token: this.sharedDetail.data.attributes.token,
|
||||
id: this.sharedDetail.data.attributes.item_id
|
||||
}
|
||||
})
|
||||
},
|
||||
dragLeave() {
|
||||
this.area = false
|
||||
},
|
||||
dragEnter() {
|
||||
if (this.draggedItem && this.draggedItem.type !== 'folder') return
|
||||
name: 'NavigationSharePanel',
|
||||
components: {
|
||||
TreeMenuNavigator,
|
||||
ContentSidebar,
|
||||
ContentGroup,
|
||||
UploadCloudIcon,
|
||||
UserCheckIcon,
|
||||
FolderIcon,
|
||||
Trash2Icon,
|
||||
UsersIcon,
|
||||
HomeIcon,
|
||||
LinkIcon,
|
||||
XIcon,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['sharedDetail', 'navigation', 'clipboard', 'config', 'user']),
|
||||
favourites() {
|
||||
return this.user.data.relationships.favourites.data.attributes.folders
|
||||
},
|
||||
storage() {
|
||||
return this.$store.getters.user.data.attributes.storage
|
||||
},
|
||||
tree() {
|
||||
return this.user.data.attributes.folders
|
||||
},
|
||||
navigationTree() {
|
||||
return this.navigation ? this.navigation[0].folders : undefined
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
draggedItem: undefined,
|
||||
area: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
goHome() {
|
||||
this.$router.replace({
|
||||
name: 'Public',
|
||||
params: {
|
||||
token: this.sharedDetail.data.attributes.token,
|
||||
id: this.sharedDetail.data.attributes.item_id,
|
||||
},
|
||||
})
|
||||
},
|
||||
dragLeave() {
|
||||
this.area = false
|
||||
},
|
||||
dragEnter() {
|
||||
if (this.draggedItem && this.draggedItem.type !== 'folder') return
|
||||
|
||||
if (this.clipboard.length > 0 && this.clipboard.find(item => item.type !== 'folder')) return
|
||||
if (this.clipboard.length > 0 && this.clipboard.find((item) => item.type !== 'folder')) return
|
||||
|
||||
this.area = true
|
||||
},
|
||||
dragFinish() {
|
||||
this.area = false
|
||||
this.area = true
|
||||
},
|
||||
dragFinish() {
|
||||
this.area = false
|
||||
|
||||
events.$emit('drop')
|
||||
events.$emit('drop')
|
||||
|
||||
// Check if dragged item is folder
|
||||
if (this.draggedItem && this.draggedItem.type !== 'folder') return
|
||||
// Check if dragged item is folder
|
||||
if (this.draggedItem && this.draggedItem.type !== 'folder') return
|
||||
|
||||
// Check if folder exist in favourites
|
||||
if (this.favourites.find(folder => folder.id === this.draggedItem.id)) return
|
||||
// Check if folder exist in favourites
|
||||
if (this.favourites.find((folder) => folder.id === this.draggedItem.id)) return
|
||||
|
||||
// Prevent to move folders to self
|
||||
if (this.clipboard.length > 0 && this.clipboard.find(item => item.type !== 'folder')) return
|
||||
// Prevent to move folders to self
|
||||
if (this.clipboard.length > 0 && this.clipboard.find((item) => item.type !== 'folder')) return
|
||||
|
||||
//Add to favourites non selected folder
|
||||
if (!this.clipboard.includes(this.draggedItem)) {
|
||||
this.$store.dispatch('addToFavourites', this.draggedItem)
|
||||
}
|
||||
//Add to favourites non selected folder
|
||||
if (!this.clipboard.includes(this.draggedItem)) {
|
||||
this.$store.dispatch('addToFavourites', this.draggedItem)
|
||||
}
|
||||
|
||||
//Add to favourites selected folders
|
||||
if (this.clipboard.includes(this.draggedItem)) {
|
||||
this.$store.dispatch('addToFavourites', null)
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// Listen for dragstart folder items
|
||||
events.$on('dragstart', item => this.draggedItem = item)
|
||||
//Add to favourites selected folders
|
||||
if (this.clipboard.includes(this.draggedItem)) {
|
||||
this.$store.dispatch('addToFavourites', null)
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// Listen for dragstart folder items
|
||||
events.$on('dragstart', (item) => (this.draggedItem = item))
|
||||
|
||||
// Get folder tree
|
||||
this.$store.dispatch('getFolderTree')
|
||||
}
|
||||
// Get folder tree
|
||||
this.$store.dispatch('getFolderTree')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.empty-note {
|
||||
&.navigator {
|
||||
padding: 5px 25px 10px;
|
||||
}
|
||||
|
||||
.empty-note {
|
||||
&.favourites {
|
||||
padding: 5px 23px 10px;
|
||||
}
|
||||
}
|
||||
|
||||
&.navigator {
|
||||
padding: 5px 25px 10px;
|
||||
}
|
||||
.navigator {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
&.favourites {
|
||||
padding: 5px 23px 10px;
|
||||
}
|
||||
}
|
||||
@media only screen and (max-width: 1024px) {
|
||||
.empty-note {
|
||||
&.navigator {
|
||||
padding: 5px 20px 10px;
|
||||
}
|
||||
|
||||
.navigator {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
}
|
||||
&.favourites {
|
||||
padding: 5px 18px 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 1024px) {
|
||||
// Transition
|
||||
.folder-item-move {
|
||||
transition: all 300s ease;
|
||||
}
|
||||
|
||||
.empty-note {
|
||||
.folder-item-enter-active {
|
||||
transition: all 300ms ease;
|
||||
}
|
||||
|
||||
&.navigator {
|
||||
padding: 5px 20px 10px;
|
||||
}
|
||||
.folder-item-leave-active {
|
||||
transition: all 300ms;
|
||||
}
|
||||
|
||||
&.favourites {
|
||||
padding: 5px 18px 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.folder-item-enter, .folder-item-leave-to /* .list-leave-active below version 2.1.8 */ {
|
||||
opacity: 0;
|
||||
transform: translateX(30px);
|
||||
}
|
||||
|
||||
// Transition
|
||||
.folder-item-move {
|
||||
transition: all 300s ease;
|
||||
}
|
||||
|
||||
.folder-item-enter-active {
|
||||
transition: all 300ms ease;
|
||||
}
|
||||
|
||||
.folder-item-leave-active {
|
||||
transition: all 300ms;
|
||||
}
|
||||
|
||||
.folder-item-enter, .folder-item-leave-to /* .list-leave-active below version 2.1.8 */
|
||||
{
|
||||
opacity: 0;
|
||||
transform: translateX(30px);
|
||||
}
|
||||
|
||||
.folder-item-leave-active {
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
.folder-item-leave-active {
|
||||
position: absolute;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,211 +1,219 @@
|
||||
<template>
|
||||
<ContentSidebar v-if="isVisibleNavigationBars" class="relative">
|
||||
<ContentSidebar v-if="isVisibleNavigationBars" class="relative">
|
||||
<!--Full screen button-->
|
||||
<div @click="toggleNavigationBars" class="absolute top-2.5 right-0 inline-block cursor-pointer p-3 opacity-0 transition-all duration-200 hover:opacity-70">
|
||||
<chevrons-left-icon size="18" />
|
||||
</div>
|
||||
|
||||
<!--Full screen button-->
|
||||
<div @click="toggleNavigationBars" class="inline-block absolute top-2.5 right-0 p-3 cursor-pointer transition-all duration-200 hover:opacity-70 opacity-0">
|
||||
<chevrons-left-icon size="18"/>
|
||||
</div>
|
||||
<!--Locations-->
|
||||
<ContentGroup v-for="(menu, i) in nav" :key="i" :title="menu.groupTitle" :slug="menu.groupTitle" :can-collapse="menu.groupCollapsable">
|
||||
<router-link v-for="(item, i) in menu.groupLinks" :key="i" @click.native="resetData" :to="{ name: item.route }" class="flex items-center py-2.5">
|
||||
<home-icon v-if="item.icon === 'home'" size="17" class="vue-feather icon-active mr-2.5" />
|
||||
<upload-cloud-icon v-if="item.icon === 'upload-cloud'" size="17" class="vue-feather icon-active mr-2.5" />
|
||||
<link-icon v-if="item.icon === 'link'" size="17" class="vue-feather icon-active mr-2.5" />
|
||||
<trash2-icon v-if="item.icon === 'trash'" size="17" class="vue-feather icon-active mr-2.5" />
|
||||
<users-icon size="17" v-if="item.icon === 'users'" class="vue-feather icon-active mr-2.5" />
|
||||
<user-check-icon size="17" v-if="item.icon === 'user-check'" class="vue-feather icon-active mr-2.5" />
|
||||
|
||||
<!--Locations-->
|
||||
<ContentGroup v-for="(menu, i) in nav" :key="i" :title="menu.groupTitle" :slug="menu.groupTitle" :can-collapse="menu.groupCollapsable">
|
||||
<router-link v-for="(item, i) in menu.groupLinks" :key="i" @click.native="resetData" :to="{name: item.route}" class="flex items-center py-2.5">
|
||||
<home-icon v-if="item.icon === 'home'" size="17" class="mr-2.5 vue-feather icon-active"/>
|
||||
<upload-cloud-icon v-if="item.icon === 'upload-cloud'" size="17" class="mr-2.5 vue-feather icon-active" />
|
||||
<link-icon v-if="item.icon === 'link'" size="17" class="mr-2.5 vue-feather icon-active" />
|
||||
<trash2-icon v-if="item.icon === 'trash'" size="17" class="mr-2.5 vue-feather icon-active" />
|
||||
<users-icon size="17" v-if="item.icon === 'users'" class="mr-2.5 vue-feather icon-active" />
|
||||
<user-check-icon size="17" v-if="item.icon === 'user-check'" class="mr-2.5 vue-feather icon-active" />
|
||||
<b class="text-active text-xs font-bold">
|
||||
{{ item.title }}
|
||||
</b>
|
||||
</router-link>
|
||||
</ContentGroup>
|
||||
|
||||
<b class="font-bold text-xs text-active">
|
||||
{{ item.title }}
|
||||
</b>
|
||||
</router-link>
|
||||
</ContentGroup>
|
||||
<!--Navigator-->
|
||||
<ContentGroup v-if="navigation" :title="$t('sidebar.navigator_title')" slug="navigator" :can-collapse="true">
|
||||
<small v-if="tree.length === 0" class="text-xs font-bold text-gray-500">
|
||||
{{ $t("There isn't any folder.") }}
|
||||
</small>
|
||||
<TreeMenuNavigator :depth="0" :nodes="folder" v-for="folder in tree" :key="folder.id" />
|
||||
</ContentGroup>
|
||||
|
||||
<!--Navigator-->
|
||||
<ContentGroup v-if="navigation" :title="$t('sidebar.navigator_title')" slug="navigator" :can-collapse="true">
|
||||
<small v-if="tree.length === 0" class="text-xs font-bold text-gray-500">
|
||||
{{ $t("There isn't any folder.") }}
|
||||
</small>
|
||||
<TreeMenuNavigator :depth="0" :nodes="folder" v-for="folder in tree" :key="folder.id"/>
|
||||
</ContentGroup>
|
||||
<!--Favourites-->
|
||||
<ContentGroup v-if="user" :title="$t('sidebar.favourites')" slug="favourites" :can-collapse="true">
|
||||
<div
|
||||
@dragover.prevent="dragEnter"
|
||||
@dragleave="dragLeave"
|
||||
@drop="dragFinish($event)"
|
||||
:class="{ 'border-theme': area }"
|
||||
class="border-2 border-dashed border-transparent"
|
||||
>
|
||||
<!--Empty message-->
|
||||
<small v-if="favourites.length === 0" class="favourites text-xs font-bold text-gray-500" :key="0">
|
||||
{{ $t('sidebar.favourites_empty') }}
|
||||
</small>
|
||||
|
||||
<!--Favourites-->
|
||||
<ContentGroup v-if="user" :title="$t('sidebar.favourites')" slug="favourites" :can-collapse="true">
|
||||
|
||||
<div @dragover.prevent="dragEnter" @dragleave="dragLeave" @drop="dragFinish($event)" :class="{'border-theme': area }" class="border-2 border-transparent border-dashed">
|
||||
|
||||
<!--Empty message-->
|
||||
<small v-if="favourites.length === 0" class="text-xs font-bold text-gray-500 favourites" :key="0">
|
||||
{{ $t('sidebar.favourites_empty') }}
|
||||
</small>
|
||||
|
||||
<!--Folder item-->
|
||||
<div @click="goToFolder(folder)" v-for="folder in favourites" :key="folder.data.id" class="group flex items-center justify-between py-2.5 cursor-pointer">
|
||||
<div class="flex items-center">
|
||||
<folder-icon size="17" class="mr-2.5 vue-feather" :class="{'text-theme': $route.params.id === folder.data.id}" />
|
||||
<span class="font-bold text-xs max-w-1 overflow-hidden text-ellipsis whitespace-nowrap" :class="{'text-theme': $route.params.id === folder.data.id}">
|
||||
{{ folder.data.attributes.name }}
|
||||
</span>
|
||||
</div>
|
||||
<x-icon @click.stop="$removeFavourite(folder)" size="12" class="mr-5 group-hover:opacity-100 opacity-0" />
|
||||
</div>
|
||||
</div>
|
||||
</ContentGroup>
|
||||
</ContentSidebar>
|
||||
<!--Folder item-->
|
||||
<div @click="goToFolder(folder)" v-for="folder in favourites" :key="folder.data.id" class="group flex cursor-pointer items-center justify-between py-2.5">
|
||||
<div class="flex items-center">
|
||||
<folder-icon
|
||||
size="17"
|
||||
class="vue-feather mr-2.5"
|
||||
:class="{
|
||||
'text-theme': $route.params.id === folder.data.id,
|
||||
}"
|
||||
/>
|
||||
<span
|
||||
class="max-w-1 overflow-hidden text-ellipsis whitespace-nowrap text-xs font-bold"
|
||||
:class="{
|
||||
'text-theme': $route.params.id === folder.data.id,
|
||||
}"
|
||||
>
|
||||
{{ folder.data.attributes.name }}
|
||||
</span>
|
||||
</div>
|
||||
<x-icon @click.stop="$removeFavourite(folder)" size="12" class="mr-5 opacity-0 group-hover:opacity-100" />
|
||||
</div>
|
||||
</div>
|
||||
</ContentGroup>
|
||||
</ContentSidebar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ChevronsLeftIcon, FolderIcon, HomeIcon, LinkIcon, Trash2Icon, UploadCloudIcon, UserCheckIcon, UsersIcon, XIcon} from "vue-feather-icons";
|
||||
import TreeMenuNavigator from "../../../components/Others/TreeMenuNavigator";
|
||||
import ContentSidebar from "../../../components/Sidebar/ContentSidebar";
|
||||
import ContentGroup from "../../../components/Sidebar/ContentGroup";
|
||||
import {events} from "../../../bus";
|
||||
import {mapGetters} from "vuex";
|
||||
import { ChevronsLeftIcon, FolderIcon, HomeIcon, LinkIcon, Trash2Icon, UploadCloudIcon, UserCheckIcon, UsersIcon, XIcon } from 'vue-feather-icons'
|
||||
import TreeMenuNavigator from '../../../components/Others/TreeMenuNavigator'
|
||||
import ContentSidebar from '../../../components/Sidebar/ContentSidebar'
|
||||
import ContentGroup from '../../../components/Sidebar/ContentGroup'
|
||||
import { events } from '../../../bus'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: "PanelNavigationFiles",
|
||||
components: {
|
||||
TreeMenuNavigator,
|
||||
ContentSidebar,
|
||||
ContentGroup,
|
||||
ChevronsLeftIcon,
|
||||
UploadCloudIcon,
|
||||
UserCheckIcon,
|
||||
FolderIcon,
|
||||
Trash2Icon,
|
||||
UsersIcon,
|
||||
HomeIcon,
|
||||
LinkIcon,
|
||||
XIcon,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'isVisibleNavigationBars',
|
||||
'navigation',
|
||||
'clipboard',
|
||||
'config',
|
||||
'user',
|
||||
]),
|
||||
favourites() {
|
||||
return this.user.data.relationships.favourites.data
|
||||
},
|
||||
storage() {
|
||||
return this.$store.getters.user.data.attributes.storage
|
||||
},
|
||||
tree() {
|
||||
return {
|
||||
'RecentUploads': this.navigation[0].folders,
|
||||
'MySharedItems': this.navigation[0].folders,
|
||||
'Trash': this.navigation[0].folders,
|
||||
'Public': this.navigation[0].folders,
|
||||
'Files': this.navigation[0].folders,
|
||||
'TeamFolders': this.navigation[1].folders,
|
||||
'SharedWithMe': this.navigation[2].folders,
|
||||
}[this.$route.name]
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
draggedItem: undefined,
|
||||
area: false,
|
||||
nav: [
|
||||
{
|
||||
groupCollapsable: false,
|
||||
groupTitle: this.$t('sidebar.locations_title'),
|
||||
groupLinks: [
|
||||
{
|
||||
icon: 'home',
|
||||
route: 'Files',
|
||||
title: this.$t('sidebar.home'),
|
||||
},
|
||||
{
|
||||
icon: 'upload-cloud',
|
||||
route: 'RecentUploads',
|
||||
title: this.$t('sidebar.latest'),
|
||||
},
|
||||
{
|
||||
icon: 'link',
|
||||
route: 'MySharedItems',
|
||||
title: this.$t('sidebar.my_shared'),
|
||||
},
|
||||
{
|
||||
icon: 'trash',
|
||||
route: 'Trash',
|
||||
title: this.$t('locations.trash'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupCollapsable: true,
|
||||
groupTitle: this.$t('Collaboration'),
|
||||
groupLinks: [
|
||||
{
|
||||
icon: 'users',
|
||||
route: 'TeamFolders',
|
||||
title: this.$t('Team Folders'),
|
||||
},
|
||||
{
|
||||
icon: 'user-check',
|
||||
route: 'SharedWithMe',
|
||||
title: this.$t('Shared with Me'),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleNavigationBars() {
|
||||
this.$store.dispatch('toggleNavigationBars')
|
||||
},
|
||||
resetData() {
|
||||
this.$store.commit('SET_CURRENT_TEAM_FOLDER', null)
|
||||
this.$store.commit('CLIPBOARD_CLEAR')
|
||||
},
|
||||
goToFolder(folder) {
|
||||
this.$router.push({name: 'Files', params: {id: folder.data.id}})
|
||||
},
|
||||
dragLeave() {
|
||||
this.area = false
|
||||
},
|
||||
dragEnter() {
|
||||
if (this.draggedItem && this.draggedItem.type !== 'folder') return
|
||||
name: 'PanelNavigationFiles',
|
||||
components: {
|
||||
TreeMenuNavigator,
|
||||
ContentSidebar,
|
||||
ContentGroup,
|
||||
ChevronsLeftIcon,
|
||||
UploadCloudIcon,
|
||||
UserCheckIcon,
|
||||
FolderIcon,
|
||||
Trash2Icon,
|
||||
UsersIcon,
|
||||
HomeIcon,
|
||||
LinkIcon,
|
||||
XIcon,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['isVisibleNavigationBars', 'navigation', 'clipboard', 'config', 'user']),
|
||||
favourites() {
|
||||
return this.user.data.relationships.favourites.data
|
||||
},
|
||||
storage() {
|
||||
return this.$store.getters.user.data.attributes.storage
|
||||
},
|
||||
tree() {
|
||||
return {
|
||||
RecentUploads: this.navigation[0].folders,
|
||||
MySharedItems: this.navigation[0].folders,
|
||||
Trash: this.navigation[0].folders,
|
||||
Public: this.navigation[0].folders,
|
||||
Files: this.navigation[0].folders,
|
||||
TeamFolders: this.navigation[1].folders,
|
||||
SharedWithMe: this.navigation[2].folders,
|
||||
}[this.$route.name]
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
draggedItem: undefined,
|
||||
area: false,
|
||||
nav: [
|
||||
{
|
||||
groupCollapsable: false,
|
||||
groupTitle: this.$t('sidebar.locations_title'),
|
||||
groupLinks: [
|
||||
{
|
||||
icon: 'home',
|
||||
route: 'Files',
|
||||
title: this.$t('sidebar.home'),
|
||||
},
|
||||
{
|
||||
icon: 'upload-cloud',
|
||||
route: 'RecentUploads',
|
||||
title: this.$t('sidebar.latest'),
|
||||
},
|
||||
{
|
||||
icon: 'link',
|
||||
route: 'MySharedItems',
|
||||
title: this.$t('sidebar.my_shared'),
|
||||
},
|
||||
{
|
||||
icon: 'trash',
|
||||
route: 'Trash',
|
||||
title: this.$t('locations.trash'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
groupCollapsable: true,
|
||||
groupTitle: this.$t('Collaboration'),
|
||||
groupLinks: [
|
||||
{
|
||||
icon: 'users',
|
||||
route: 'TeamFolders',
|
||||
title: this.$t('Team Folders'),
|
||||
},
|
||||
{
|
||||
icon: 'user-check',
|
||||
route: 'SharedWithMe',
|
||||
title: this.$t('Shared with Me'),
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleNavigationBars() {
|
||||
this.$store.dispatch('toggleNavigationBars')
|
||||
},
|
||||
resetData() {
|
||||
this.$store.commit('SET_CURRENT_TEAM_FOLDER', null)
|
||||
this.$store.commit('CLIPBOARD_CLEAR')
|
||||
},
|
||||
goToFolder(folder) {
|
||||
this.$router.push({ name: 'Files', params: { id: folder.data.id } })
|
||||
},
|
||||
dragLeave() {
|
||||
this.area = false
|
||||
},
|
||||
dragEnter() {
|
||||
if (this.draggedItem && this.draggedItem.type !== 'folder') return
|
||||
|
||||
if (this.clipboard.length > 0 && this.clipboard.find(item => item.type !== 'folder')) return
|
||||
if (this.clipboard.length > 0 && this.clipboard.find((item) => item.type !== 'folder')) return
|
||||
|
||||
this.area = true
|
||||
},
|
||||
dragFinish() {
|
||||
this.area = false
|
||||
this.area = true
|
||||
},
|
||||
dragFinish() {
|
||||
this.area = false
|
||||
|
||||
events.$emit('drop')
|
||||
events.$emit('drop')
|
||||
|
||||
// Check if dragged item is folder
|
||||
if (this.draggedItem && this.draggedItem.type !== 'folder') return
|
||||
// Check if dragged item is folder
|
||||
if (this.draggedItem && this.draggedItem.type !== 'folder') return
|
||||
|
||||
// Check if folder exist in favourites
|
||||
if (this.favourites.find(folder => folder.id === this.draggedItem.id)) return
|
||||
// Check if folder exist in favourites
|
||||
if (this.favourites.find((folder) => folder.id === this.draggedItem.id)) return
|
||||
|
||||
// Prevent to move folders to self
|
||||
if (this.clipboard.length > 0 && this.clipboard.find(item => item.type !== 'folder')) return
|
||||
// Prevent to move folders to self
|
||||
if (this.clipboard.length > 0 && this.clipboard.find((item) => item.type !== 'folder')) return
|
||||
|
||||
//Add to favourites non selected folder
|
||||
if (!this.clipboard.includes(this.draggedItem)) {
|
||||
this.$store.dispatch('addToFavourites', this.draggedItem)
|
||||
}
|
||||
//Add to favourites non selected folder
|
||||
if (!this.clipboard.includes(this.draggedItem)) {
|
||||
this.$store.dispatch('addToFavourites', this.draggedItem)
|
||||
}
|
||||
|
||||
//Add to favourites selected folders
|
||||
if (this.clipboard.includes(this.draggedItem)) {
|
||||
this.$store.dispatch('addToFavourites', null)
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// Listen for dragstart folder items
|
||||
events.$on('dragstart', item => this.draggedItem = item)
|
||||
//Add to favourites selected folders
|
||||
if (this.clipboard.includes(this.draggedItem)) {
|
||||
this.$store.dispatch('addToFavourites', null)
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// Listen for dragstart folder items
|
||||
events.$on('dragstart', (item) => (this.draggedItem = item))
|
||||
|
||||
this.$store.dispatch('getFolderTree')
|
||||
}
|
||||
this.$store.dispatch('getFolderTree')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
</script>
|
||||
|
||||
@@ -1,215 +1,238 @@
|
||||
<template>
|
||||
<div>
|
||||
<MobileContextMenu>
|
||||
<OptionGroup v-if="item && isFolder">
|
||||
<Option @click.native="addToFavourites" :title="isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites')" icon="favourites" />
|
||||
<div>
|
||||
<MobileContextMenu>
|
||||
<OptionGroup v-if="item && isFolder">
|
||||
<Option
|
||||
@click.native="addToFavourites"
|
||||
:title="isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites')"
|
||||
icon="favourites"
|
||||
/>
|
||||
</OptionGroup>
|
||||
|
||||
<OptionGroup v-if="item">
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup v-if="item">
|
||||
<Option @click.native="$shareFileOrFolder(item)" :title="item.data.relationships.shared ? $t('context_menu.share_edit') : $t('context_menu.share')" icon="share" />
|
||||
<Option @click.native="$convertAsTeamFolder(item)" v-if="isFolder" :title="$t('Convert as Team Folder')" icon="users" />
|
||||
</OptionGroup>
|
||||
<OptionGroup v-if="item">
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup v-if="item">
|
||||
<Option @click.native="$shareFileOrFolder(item)" :title="item.data.relationships.shared ? $t('context_menu.share_edit') : $t('context_menu.share')" icon="share" />
|
||||
<Option @click.native="$convertAsTeamFolder(item)" v-if="isFolder" :title="$t('Convert as Team Folder')" icon="users" />
|
||||
</OptionGroup>
|
||||
|
||||
<OptionGroup v-if="item">
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</MobileContextMenu>
|
||||
</MobileContextMenu>
|
||||
|
||||
<MobileCreateMenu>
|
||||
<OptionGroup>
|
||||
<OptionUpload :class="{'is-inactive': !hasCapacity }" :title="$t('actions.upload')" type="file" :is-hover-disabled="true" />
|
||||
<OptionUpload :title="$t('actions.upload_folder')" type="folder" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.stop.native="$createTeamFolder" :title="$t('Create Team Folder')" icon="users" :is-hover-disabled="true" />
|
||||
<Option @click.stop.native="createFolder" :title="$t('actions.create_folder')" icon="folder-plus" :is-hover-disabled="true" />
|
||||
</OptionGroup>
|
||||
</MobileCreateMenu>
|
||||
<MobileCreateMenu>
|
||||
<OptionGroup>
|
||||
<OptionUpload :class="{ 'is-inactive': !hasCapacity }" :title="$t('actions.upload')" type="file" :is-hover-disabled="true" />
|
||||
<OptionUpload :title="$t('actions.upload_folder')" type="folder" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.stop.native="$createTeamFolder" :title="$t('Create Team Folder')" icon="users" :is-hover-disabled="true" />
|
||||
<Option @click.stop.native="createFolder" :title="$t('actions.create_folder')" icon="folder-plus" :is-hover-disabled="true" />
|
||||
</OptionGroup>
|
||||
</MobileCreateMenu>
|
||||
|
||||
<MobileMultiSelectToolbar>
|
||||
<ToolbarButton @click.native="$moveFileOrFolder(clipboard)" class="action-btn" source="move" :action="$t('actions.move')" :class="{'is-inactive' : clipboard.length < 1}" />
|
||||
<ToolbarButton @click.native="$deleteFileOrFolder(clipboard)" class="action-btn" source="trash" :class="{'is-inactive' : clipboard.length < 1}" :action="$t('actions.delete')" />
|
||||
<MobileMultiSelectToolbar>
|
||||
<ToolbarButton
|
||||
@click.native="$moveFileOrFolder(clipboard)"
|
||||
class="action-btn"
|
||||
source="move"
|
||||
:action="$t('actions.move')"
|
||||
:class="{ 'is-inactive': clipboard.length < 1 }"
|
||||
/>
|
||||
<ToolbarButton
|
||||
@click.native="$deleteFileOrFolder(clipboard)"
|
||||
class="action-btn"
|
||||
source="trash"
|
||||
:class="{ 'is-inactive': clipboard.length < 1 }"
|
||||
:action="$t('actions.delete')"
|
||||
/>
|
||||
<ToolbarButton @click.native="$downloadSelection(item)" class="action-btn" source="download" :action="$t('actions.download')" />
|
||||
</MobileMultiSelectToolbar>
|
||||
</MobileMultiSelectToolbar>
|
||||
|
||||
<ContextMenu>
|
||||
<template v-slot:empty-select>
|
||||
<OptionGroup>
|
||||
<OptionUpload :title="$t('actions.upload')" type="file" />
|
||||
<OptionUpload :title="$t('actions.upload_folder')" type="folder" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$createFolder" :title="$t('context_menu.create_folder')" icon="create-folder" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
<ContextMenu>
|
||||
<template v-slot:empty-select>
|
||||
<OptionGroup>
|
||||
<OptionUpload :title="$t('actions.upload')" type="file" />
|
||||
<OptionUpload :title="$t('actions.upload_folder')" type="folder" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$createFolder" :title="$t('context_menu.create_folder')" icon="create-folder" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
|
||||
<template v-slot:single-select v-if="item">
|
||||
<OptionGroup v-if="isFolder">
|
||||
<Option @click.native="addToFavourites" :title="isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites')" icon="favourites" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$shareFileOrFolder(item)" :title="item.data.relationships.shared ? $t('context_menu.share_edit') : $t('context_menu.share')" icon="share" />
|
||||
<Option @click.native="$convertAsTeamFolder(item)" v-if="isFolder" :title="$t('Convert as Team Folder')" icon="user-plus" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$openInDetailPanel(item)" :title="$t('context_menu.detail')" icon="detail" />
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
<template v-slot:single-select v-if="item">
|
||||
<OptionGroup v-if="isFolder">
|
||||
<Option
|
||||
@click.native="addToFavourites"
|
||||
:title="isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites')"
|
||||
icon="favourites"
|
||||
/>
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option
|
||||
@click.native="$shareFileOrFolder(item)"
|
||||
:title="item.data.relationships.shared ? $t('context_menu.share_edit') : $t('context_menu.share')"
|
||||
icon="share"
|
||||
/>
|
||||
<Option @click.native="$convertAsTeamFolder(item)" v-if="isFolder" :title="$t('Convert as Team Folder')" icon="user-plus" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$openInDetailPanel(item)" :title="$t('context_menu.detail')" icon="detail" />
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
|
||||
<template v-slot:multiple-select v-if="item">
|
||||
<OptionGroup v-if="!hasFile">
|
||||
<Option @click.native="addToFavourites" :title="isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites')" icon="favourites" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
</ContextMenu>
|
||||
<template v-slot:multiple-select v-if="item">
|
||||
<OptionGroup v-if="!hasFile">
|
||||
<Option
|
||||
@click.native="addToFavourites"
|
||||
:title="isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites')"
|
||||
icon="favourites"
|
||||
/>
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
</ContextMenu>
|
||||
|
||||
<FileActionsMobile>
|
||||
<MobileActionButton @click.native="$openSpotlight()" icon="search">
|
||||
{{ $t('Spotlight') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-filter')" :icon="$getCurrentSectionIcon()">
|
||||
{{ $getCurrentSectionName() }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('create-list')" v-if="$checkPermission(['master', 'editor'])" icon="cloud-plus">
|
||||
{{ $t('mobile.create') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$enableMultiSelectMode" icon="check-square">
|
||||
{{ $t('context_menu.select') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-sorting')" icon="preview-sorting">
|
||||
{{ $t('preview_sorting.preview_sorting_button') }}
|
||||
</MobileActionButton>
|
||||
</FileActionsMobile>
|
||||
<FileActionsMobile>
|
||||
<MobileActionButton @click.native="$openSpotlight()" icon="search">
|
||||
{{ $t('Spotlight') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-filter')" :icon="$getCurrentSectionIcon()">
|
||||
{{ $getCurrentSectionName() }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('create-list')" v-if="$checkPermission(['master', 'editor'])" icon="cloud-plus">
|
||||
{{ $t('mobile.create') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$enableMultiSelectMode" icon="check-square">
|
||||
{{ $t('context_menu.select') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-sorting')" icon="preview-sorting">
|
||||
{{ $t('preview_sorting.preview_sorting_button') }}
|
||||
</MobileActionButton>
|
||||
</FileActionsMobile>
|
||||
|
||||
<EmptyFilePage>
|
||||
<h1 class="title">
|
||||
{{ $t('empty_page.title') }}
|
||||
</h1>
|
||||
<p class="description">
|
||||
{{ $t('empty_page.description') }}
|
||||
</p>
|
||||
<ButtonUpload button-style="theme">
|
||||
{{ $t('empty_page.call_to_action') }}
|
||||
</ButtonUpload>
|
||||
</EmptyFilePage>
|
||||
<EmptyFilePage>
|
||||
<h1 class="title">
|
||||
{{ $t('empty_page.title') }}
|
||||
</h1>
|
||||
<p class="description">
|
||||
{{ $t('empty_page.description') }}
|
||||
</p>
|
||||
<ButtonUpload button-style="theme">
|
||||
{{ $t('empty_page.call_to_action') }}
|
||||
</ButtonUpload>
|
||||
</EmptyFilePage>
|
||||
|
||||
<FileBrowser />
|
||||
</div>
|
||||
<FileBrowser />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EmptyFilePage from "../../components/FilesView/EmptyFilePage";
|
||||
import FileActionsMobile from "../../components/FilesView/FileActionsMobile";
|
||||
import MobileActionButtonUpload from "../../components/FilesView/MobileActionButtonUpload";
|
||||
import MobileMultiSelectToolbar from "../../components/FilesView/MobileMultiSelectToolbar";
|
||||
import MobileActionButton from "../../components/FilesView/MobileActionButton";
|
||||
import MobileContextMenu from "../../components/FilesView/MobileContextMenu";
|
||||
import MobileCreateMenu from "../../components/FilesView/MobileCreateMenu";
|
||||
import ButtonUpload from "../../components/FilesView/ButtonUpload";
|
||||
import ToolbarButton from "../../components/FilesView/ToolbarButton";
|
||||
import OptionUpload from "../../components/FilesView/OptionUpload";
|
||||
import FileBrowser from "../../components/FilesView/FileBrowser";
|
||||
import ContextMenu from "../../components/FilesView/ContextMenu";
|
||||
import OptionGroup from "../../components/FilesView/OptionGroup";
|
||||
import Option from "../../components/FilesView/Option";
|
||||
import { mapGetters } from 'vuex'
|
||||
import {events} from "../../bus";
|
||||
import EmptyFilePage from '../../components/FilesView/EmptyFilePage'
|
||||
import FileActionsMobile from '../../components/FilesView/FileActionsMobile'
|
||||
import MobileActionButtonUpload from '../../components/FilesView/MobileActionButtonUpload'
|
||||
import MobileMultiSelectToolbar from '../../components/FilesView/MobileMultiSelectToolbar'
|
||||
import MobileActionButton from '../../components/FilesView/MobileActionButton'
|
||||
import MobileContextMenu from '../../components/FilesView/MobileContextMenu'
|
||||
import MobileCreateMenu from '../../components/FilesView/MobileCreateMenu'
|
||||
import ButtonUpload from '../../components/FilesView/ButtonUpload'
|
||||
import ToolbarButton from '../../components/FilesView/ToolbarButton'
|
||||
import OptionUpload from '../../components/FilesView/OptionUpload'
|
||||
import FileBrowser from '../../components/FilesView/FileBrowser'
|
||||
import ContextMenu from '../../components/FilesView/ContextMenu'
|
||||
import OptionGroup from '../../components/FilesView/OptionGroup'
|
||||
import Option from '../../components/FilesView/Option'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { events } from '../../bus'
|
||||
|
||||
export default {
|
||||
name: 'Files',
|
||||
components: {
|
||||
EmptyFilePage,
|
||||
FileActionsMobile,
|
||||
MobileActionButtonUpload,
|
||||
MobileMultiSelectToolbar,
|
||||
MobileActionButton,
|
||||
MobileContextMenu,
|
||||
MobileCreateMenu,
|
||||
ToolbarButton,
|
||||
ButtonUpload,
|
||||
OptionUpload,
|
||||
OptionGroup,
|
||||
FileBrowser,
|
||||
ContextMenu,
|
||||
Option,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'fastPreview',
|
||||
'clipboard',
|
||||
'config',
|
||||
'user',
|
||||
]),
|
||||
hasCapacity() {
|
||||
// Check if storage limitation is set
|
||||
if (!this.config.storageLimit) return true
|
||||
export default {
|
||||
name: 'Files',
|
||||
components: {
|
||||
EmptyFilePage,
|
||||
FileActionsMobile,
|
||||
MobileActionButtonUpload,
|
||||
MobileMultiSelectToolbar,
|
||||
MobileActionButton,
|
||||
MobileContextMenu,
|
||||
MobileCreateMenu,
|
||||
ToolbarButton,
|
||||
ButtonUpload,
|
||||
OptionUpload,
|
||||
OptionGroup,
|
||||
FileBrowser,
|
||||
ContextMenu,
|
||||
Option,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['fastPreview', 'clipboard', 'config', 'user']),
|
||||
hasCapacity() {
|
||||
// Check if storage limitation is set
|
||||
if (!this.config.storageLimit) return true
|
||||
|
||||
// Check if user has storage
|
||||
return this.user && this.user.data.attributes.storage.used <= 100
|
||||
},
|
||||
isFolder() {
|
||||
return this.item && this.item.data.type === 'folder'
|
||||
},
|
||||
isInFavourites() {
|
||||
return this.favourites.find((el) => el.id === this.item.data.id)
|
||||
},
|
||||
hasFile() {
|
||||
return this.clipboard.find(item => item.data.type !== 'folder')
|
||||
},
|
||||
favourites() {
|
||||
return this.user.data.relationships.favourites.data
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
item: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addToFavourites() {
|
||||
// Check if folder is in favourites and then add/remove from favourites
|
||||
if (this.favourites && !this.favourites.find(el => el.id === this.item.data.id)) {
|
||||
// Add to favourite folder that is not selected
|
||||
if (!this.clipboard.includes(this.item)) {
|
||||
this.$store.dispatch('addToFavourites', this.item)
|
||||
}
|
||||
// Check if user has storage
|
||||
return this.user && this.user.data.attributes.storage.used <= 100
|
||||
},
|
||||
isFolder() {
|
||||
return this.item && this.item.data.type === 'folder'
|
||||
},
|
||||
isInFavourites() {
|
||||
return this.favourites.find((el) => el.id === this.item.data.id)
|
||||
},
|
||||
hasFile() {
|
||||
return this.clipboard.find((item) => item.data.type !== 'folder')
|
||||
},
|
||||
favourites() {
|
||||
return this.user.data.relationships.favourites.data
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
item: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addToFavourites() {
|
||||
// Check if folder is in favourites and then add/remove from favourites
|
||||
if (this.favourites && !this.favourites.find((el) => el.id === this.item.data.id)) {
|
||||
// Add to favourite folder that is not selected
|
||||
if (!this.clipboard.includes(this.item)) {
|
||||
this.$store.dispatch('addToFavourites', this.item)
|
||||
}
|
||||
|
||||
// Add to favourites all selected folders
|
||||
if (this.clipboard.includes(this.item)) {
|
||||
this.$store.dispatch('addToFavourites', null)
|
||||
}
|
||||
} else {
|
||||
this.$store.dispatch('removeFromFavourites', this.item)
|
||||
}
|
||||
},
|
||||
createFolder() {
|
||||
events.$emit('popup:open', {name: 'create-folder'})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$store.dispatch('getFolder', this.$route.params.id)
|
||||
// Add to favourites all selected folders
|
||||
if (this.clipboard.includes(this.item)) {
|
||||
this.$store.dispatch('addToFavourites', null)
|
||||
}
|
||||
} else {
|
||||
this.$store.dispatch('removeFromFavourites', this.item)
|
||||
}
|
||||
},
|
||||
createFolder() {
|
||||
events.$emit('popup:open', { name: 'create-folder' })
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$store.dispatch('getFolder', this.$route.params.id)
|
||||
|
||||
events.$on('context-menu:show', (event, item) => this.item = item)
|
||||
events.$on('context-menu:current-folder', folder => this.item = folder)
|
||||
events.$on('mobile-context-menu:show', item => this.item = item)
|
||||
}
|
||||
}
|
||||
events.$on('context-menu:show', (event, item) => (this.item = item))
|
||||
events.$on('context-menu:current-folder', (folder) => (this.item = folder))
|
||||
events.$on('mobile-context-menu:show', (item) => (this.item = item))
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,157 +1,170 @@
|
||||
<template>
|
||||
<div>
|
||||
<ContextMenu>
|
||||
<template v-slot:single-select v-if="item">
|
||||
<OptionGroup v-if="isFolder">
|
||||
<Option @click.native="addToFavourites" :title="isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites')" icon="favourites" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$shareFileOrFolder(item)" :title="item.data.relationships.shared ? $t('context_menu.share_edit') : $t('context_menu.share')" icon="share" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$openInDetailPanel(item)" :title="$t('context_menu.detail')" icon="detail" />
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
<div>
|
||||
<ContextMenu>
|
||||
<template v-slot:single-select v-if="item">
|
||||
<OptionGroup v-if="isFolder">
|
||||
<Option
|
||||
@click.native="addToFavourites"
|
||||
:title="isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites')"
|
||||
icon="favourites"
|
||||
/>
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option
|
||||
@click.native="$shareFileOrFolder(item)"
|
||||
:title="item.data.relationships.shared ? $t('context_menu.share_edit') : $t('context_menu.share')"
|
||||
icon="share"
|
||||
/>
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$openInDetailPanel(item)" :title="$t('context_menu.detail')" icon="detail" />
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
|
||||
<template v-slot:multiple-select v-if="item">
|
||||
<OptionGroup v-if="!hasFile">
|
||||
<Option @click.native="addToFavourites" :title="isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites')" icon="favourites" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$shareCancel" :title="$t('context_menu.share_cancel')" icon="share" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
</ContextMenu>
|
||||
<template v-slot:multiple-select v-if="item">
|
||||
<OptionGroup v-if="!hasFile">
|
||||
<Option
|
||||
@click.native="addToFavourites"
|
||||
:title="isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites')"
|
||||
icon="favourites"
|
||||
/>
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$shareCancel" :title="$t('context_menu.share_cancel')" icon="share" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
</ContextMenu>
|
||||
|
||||
<MobileContextMenu>
|
||||
<OptionGroup v-if="isFolder">
|
||||
<Option @click.native="addToFavourites" :title="isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites')" icon="favourites" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$shareFileOrFolder(item)" :title="item && item.shared ? $t('context_menu.share_edit') : $t('context_menu.share')" icon="share" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</MobileContextMenu>
|
||||
<MobileContextMenu>
|
||||
<OptionGroup v-if="isFolder">
|
||||
<Option
|
||||
@click.native="addToFavourites"
|
||||
:title="isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites')"
|
||||
icon="favourites"
|
||||
/>
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$shareFileOrFolder(item)" :title="item && item.shared ? $t('context_menu.share_edit') : $t('context_menu.share')" icon="share" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</MobileContextMenu>
|
||||
|
||||
<FileActionsMobile>
|
||||
<MobileActionButton @click.native="$openSpotlight()" icon="search">
|
||||
{{ $t('Spotlight')}}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-filter')" :icon="$getCurrentSectionIcon()">
|
||||
{{ $getCurrentSectionName() }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$enableMultiSelectMode" icon="check-square">
|
||||
{{ $t('context_menu.select') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-sorting')" icon="preview-sorting">
|
||||
{{ $t('preview_sorting.preview_sorting_button') }}
|
||||
</MobileActionButton>
|
||||
</FileActionsMobile>
|
||||
<FileActionsMobile>
|
||||
<MobileActionButton @click.native="$openSpotlight()" icon="search">
|
||||
{{ $t('Spotlight') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-filter')" :icon="$getCurrentSectionIcon()">
|
||||
{{ $getCurrentSectionName() }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$enableMultiSelectMode" icon="check-square">
|
||||
{{ $t('context_menu.select') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-sorting')" icon="preview-sorting">
|
||||
{{ $t('preview_sorting.preview_sorting_button') }}
|
||||
</MobileActionButton>
|
||||
</FileActionsMobile>
|
||||
|
||||
<EmptyFilePage>
|
||||
<h1 class="title">{{ $t('shared.empty_shared') }}</h1>
|
||||
</EmptyFilePage>
|
||||
<EmptyFilePage>
|
||||
<h1 class="title">{{ $t('shared.empty_shared') }}</h1>
|
||||
</EmptyFilePage>
|
||||
|
||||
<FileBrowser />
|
||||
<FileBrowser />
|
||||
|
||||
<MobileMultiSelectToolbar>
|
||||
<ToolbarButton @click.native="$downloadSelection(item)" class="action-btn" source="download" :action="$t('actions.download')" />
|
||||
<ToolbarButton @click.native="$shareCancel" class="action-btn" source="shared-off" />
|
||||
</MobileMultiSelectToolbar>
|
||||
</div>
|
||||
<MobileMultiSelectToolbar>
|
||||
<ToolbarButton @click.native="$downloadSelection(item)" class="action-btn" source="download" :action="$t('actions.download')" />
|
||||
<ToolbarButton @click.native="$shareCancel" class="action-btn" source="shared-off" />
|
||||
</MobileMultiSelectToolbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EmptyFilePage from "../../components/FilesView/EmptyFilePage";
|
||||
import FileActionsMobile from "../../components/FilesView/FileActionsMobile";
|
||||
import MobileActionButtonUpload from "../../components/FilesView/MobileActionButtonUpload";
|
||||
import MobileActionButton from "../../components/FilesView/MobileActionButton";
|
||||
import MobileMultiSelectToolbar from "../../components/FilesView/MobileMultiSelectToolbar";
|
||||
import MobileContextMenu from "../../components/FilesView/MobileContextMenu";
|
||||
import ToolbarButton from "../../components/FilesView/ToolbarButton";
|
||||
import FileBrowser from "../../components/FilesView/FileBrowser";
|
||||
import ContextMenu from "../../components/FilesView/ContextMenu";
|
||||
import OptionGroup from "../../components/FilesView/OptionGroup";
|
||||
import Option from "../../components/FilesView/Option";
|
||||
import { mapGetters } from 'vuex'
|
||||
import {events} from "../../bus";
|
||||
import EmptyFilePage from '../../components/FilesView/EmptyFilePage'
|
||||
import FileActionsMobile from '../../components/FilesView/FileActionsMobile'
|
||||
import MobileActionButtonUpload from '../../components/FilesView/MobileActionButtonUpload'
|
||||
import MobileActionButton from '../../components/FilesView/MobileActionButton'
|
||||
import MobileMultiSelectToolbar from '../../components/FilesView/MobileMultiSelectToolbar'
|
||||
import MobileContextMenu from '../../components/FilesView/MobileContextMenu'
|
||||
import ToolbarButton from '../../components/FilesView/ToolbarButton'
|
||||
import FileBrowser from '../../components/FilesView/FileBrowser'
|
||||
import ContextMenu from '../../components/FilesView/ContextMenu'
|
||||
import OptionGroup from '../../components/FilesView/OptionGroup'
|
||||
import Option from '../../components/FilesView/Option'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { events } from '../../bus'
|
||||
|
||||
export default {
|
||||
name: 'MySharedItems',
|
||||
components: {
|
||||
MobileActionButtonUpload,
|
||||
MobileActionButton,
|
||||
MobileMultiSelectToolbar,
|
||||
MobileContextMenu,
|
||||
ToolbarButton,
|
||||
OptionGroup,
|
||||
FileBrowser,
|
||||
ContextMenu,
|
||||
Option,
|
||||
FileActionsMobile,
|
||||
EmptyFilePage,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'clipboard',
|
||||
'user',
|
||||
]),
|
||||
isFolder() {
|
||||
return this.item && this.item.type === 'folder'
|
||||
},
|
||||
isInFavourites() {
|
||||
return this.favourites.find(el => el.id === this.item.id)
|
||||
},
|
||||
hasFile() {
|
||||
return this.clipboard.find(item => item.type !== 'folder')
|
||||
},
|
||||
favourites() {
|
||||
return this.user.data.relationships.favourites.data.attributes.folders
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
item: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addToFavourites() {
|
||||
// Check if folder is in favourites and then add/remove from favourites
|
||||
if (this.favourites && !this.favourites.find(el => el.id === this.item.data.id)) {
|
||||
// Add to favourite folder that is not selected
|
||||
if (!this.clipboard.includes(this.item)) {
|
||||
this.$store.dispatch('addToFavourites', this.item)
|
||||
}
|
||||
export default {
|
||||
name: 'MySharedItems',
|
||||
components: {
|
||||
MobileActionButtonUpload,
|
||||
MobileActionButton,
|
||||
MobileMultiSelectToolbar,
|
||||
MobileContextMenu,
|
||||
ToolbarButton,
|
||||
OptionGroup,
|
||||
FileBrowser,
|
||||
ContextMenu,
|
||||
Option,
|
||||
FileActionsMobile,
|
||||
EmptyFilePage,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['clipboard', 'user']),
|
||||
isFolder() {
|
||||
return this.item && this.item.type === 'folder'
|
||||
},
|
||||
isInFavourites() {
|
||||
return this.favourites.find((el) => el.id === this.item.id)
|
||||
},
|
||||
hasFile() {
|
||||
return this.clipboard.find((item) => item.type !== 'folder')
|
||||
},
|
||||
favourites() {
|
||||
return this.user.data.relationships.favourites.data.attributes.folders
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
item: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addToFavourites() {
|
||||
// Check if folder is in favourites and then add/remove from favourites
|
||||
if (this.favourites && !this.favourites.find((el) => el.id === this.item.data.id)) {
|
||||
// Add to favourite folder that is not selected
|
||||
if (!this.clipboard.includes(this.item)) {
|
||||
this.$store.dispatch('addToFavourites', this.item)
|
||||
}
|
||||
|
||||
// Add to favourites all selected folders
|
||||
if (this.clipboard.includes(this.item)) {
|
||||
this.$store.dispatch('addToFavourites', null)
|
||||
}
|
||||
} else {
|
||||
this.$store.dispatch('removeFromFavourites', this.item)
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$store.dispatch('getMySharedItems')
|
||||
// Add to favourites all selected folders
|
||||
if (this.clipboard.includes(this.item)) {
|
||||
this.$store.dispatch('addToFavourites', null)
|
||||
}
|
||||
} else {
|
||||
this.$store.dispatch('removeFromFavourites', this.item)
|
||||
}
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$store.dispatch('getMySharedItems')
|
||||
|
||||
events.$on('context-menu:show', (event, item) => this.item = item)
|
||||
events.$on('mobile-context-menu:show', item => this.item = item)
|
||||
}
|
||||
}
|
||||
events.$on('context-menu:show', (event, item) => (this.item = item))
|
||||
events.$on('mobile-context-menu:show', (item) => (this.item = item))
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,183 +1,193 @@
|
||||
<template>
|
||||
<div>
|
||||
<MobileContextMenu>
|
||||
<template v-slot:editor>
|
||||
<OptionGroup>
|
||||
<Option v-if="item" @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option v-if="item" @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
<template v-slot:visitor>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
</MobileContextMenu>
|
||||
<div>
|
||||
<MobileContextMenu>
|
||||
<template v-slot:editor>
|
||||
<OptionGroup>
|
||||
<Option v-if="item" @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option v-if="item" @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
<template v-slot:visitor>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
</MobileContextMenu>
|
||||
|
||||
<MobileCreateMenu>
|
||||
<OptionGroup>
|
||||
<OptionUpload :title="$t('actions.upload')" type="file" :is-hover-disabled="true" />
|
||||
<OptionUpload :title="$t('actions.upload_folder')" type="folder" :is-hover-disabled="true" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.stop.native="createFolder" :title="$t('actions.create_folder')" icon="folder-plus" :is-hover-disabled="true" />
|
||||
</OptionGroup>
|
||||
</MobileCreateMenu>
|
||||
<MobileCreateMenu>
|
||||
<OptionGroup>
|
||||
<OptionUpload :title="$t('actions.upload')" type="file" :is-hover-disabled="true" />
|
||||
<OptionUpload :title="$t('actions.upload_folder')" type="folder" :is-hover-disabled="true" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.stop.native="createFolder" :title="$t('actions.create_folder')" icon="folder-plus" :is-hover-disabled="true" />
|
||||
</OptionGroup>
|
||||
</MobileCreateMenu>
|
||||
|
||||
<MobileMultiSelectToolbar>
|
||||
<template v-slot:visitor>
|
||||
<ToolbarButton @click.native="downloadItem" class="action-btn" source="download" :action="$t('actions.download')" />
|
||||
</template>
|
||||
<template v-slot:editor>
|
||||
<ToolbarButton @click.native="$moveFileOrFolder(clipboard)" class="action-btn" source="move" :action="$t('actions.move')" :class="{'is-inactive': clipboard.length < 1}" />
|
||||
<ToolbarButton @click.native="$deleteFileOrFolder(clipboard)" class="action-btn" source="trash" :class="{'is-inactive': clipboard.length < 1}" :action="$t('actions.delete')" />
|
||||
<ToolbarButton @click.native="downloadItem" class="action-btn" source="download" :action="$t('actions.download')" />
|
||||
</template>
|
||||
</MobileMultiSelectToolbar>
|
||||
<MobileMultiSelectToolbar>
|
||||
<template v-slot:visitor>
|
||||
<ToolbarButton @click.native="downloadItem" class="action-btn" source="download" :action="$t('actions.download')" />
|
||||
</template>
|
||||
<template v-slot:editor>
|
||||
<ToolbarButton
|
||||
@click.native="$moveFileOrFolder(clipboard)"
|
||||
class="action-btn"
|
||||
source="move"
|
||||
:action="$t('actions.move')"
|
||||
:class="{ 'is-inactive': clipboard.length < 1 }"
|
||||
/>
|
||||
<ToolbarButton
|
||||
@click.native="$deleteFileOrFolder(clipboard)"
|
||||
class="action-btn"
|
||||
source="trash"
|
||||
:class="{ 'is-inactive': clipboard.length < 1 }"
|
||||
:action="$t('actions.delete')"
|
||||
/>
|
||||
<ToolbarButton @click.native="downloadItem" class="action-btn" source="download" :action="$t('actions.download')" />
|
||||
</template>
|
||||
</MobileMultiSelectToolbar>
|
||||
|
||||
<ContextMenu>
|
||||
<template v-slot:empty-select v-if="$checkPermission('editor')">
|
||||
<OptionGroup>
|
||||
<OptionUpload :title="$t('actions.upload')" type="file" />
|
||||
<OptionUpload :title="$t('actions.upload_folder')" type="folder" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$createFolder" :title="$t('context_menu.create_folder')" icon="create-folder" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
<ContextMenu>
|
||||
<template v-slot:empty-select v-if="$checkPermission('editor')">
|
||||
<OptionGroup>
|
||||
<OptionUpload :title="$t('actions.upload')" type="file" />
|
||||
<OptionUpload :title="$t('actions.upload_folder')" type="folder" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$createFolder" :title="$t('context_menu.create_folder')" icon="create-folder" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
|
||||
<template v-slot:single-select v-if="item">
|
||||
<OptionGroup v-if="$checkPermission('editor')">
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$openInDetailPanel(item)" :title="$t('context_menu.detail')" icon="detail" />
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
<template v-slot:single-select v-if="item">
|
||||
<OptionGroup v-if="$checkPermission('editor')">
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$openInDetailPanel(item)" :title="$t('context_menu.detail')" icon="detail" />
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
|
||||
<template v-slot:multiple-select v-if="item">
|
||||
<OptionGroup v-if="$checkPermission('editor')">
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
</ContextMenu>
|
||||
<template v-slot:multiple-select v-if="item">
|
||||
<OptionGroup v-if="$checkPermission('editor')">
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
</ContextMenu>
|
||||
|
||||
<FileActionsMobile>
|
||||
<template v-if="$checkPermission('editor')">
|
||||
<MobileActionButton @click.native="$openSpotlight()" icon="search">
|
||||
{{ $t('Spotlight') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('create-list')" icon="cloud-plus">
|
||||
{{ $t('mobile.create') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$enableMultiSelectMode" icon="check-square">
|
||||
{{ $t('context_menu.select') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-sorting')" icon="preview-sorting">
|
||||
{{ $t('preview_sorting.preview_sorting_button') }}
|
||||
</MobileActionButton>
|
||||
</template>
|
||||
<template v-if="$checkPermission('visitor')">
|
||||
<MobileActionButton @click.native="$openSpotlight()" icon="search">
|
||||
{{ $t('Spotlight')}}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$enableMultiSelectMode" icon="check-square">
|
||||
{{ $t('context_menu.select') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-sorting')" icon="preview-sorting">
|
||||
{{ $t('preview_sorting.preview_sorting_button') }}
|
||||
</MobileActionButton>
|
||||
</template>
|
||||
</FileActionsMobile>
|
||||
<FileActionsMobile>
|
||||
<template v-if="$checkPermission('editor')">
|
||||
<MobileActionButton @click.native="$openSpotlight()" icon="search">
|
||||
{{ $t('Spotlight') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('create-list')" icon="cloud-plus">
|
||||
{{ $t('mobile.create') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$enableMultiSelectMode" icon="check-square">
|
||||
{{ $t('context_menu.select') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-sorting')" icon="preview-sorting">
|
||||
{{ $t('preview_sorting.preview_sorting_button') }}
|
||||
</MobileActionButton>
|
||||
</template>
|
||||
<template v-if="$checkPermission('visitor')">
|
||||
<MobileActionButton @click.native="$openSpotlight()" icon="search">
|
||||
{{ $t('Spotlight') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$enableMultiSelectMode" icon="check-square">
|
||||
{{ $t('context_menu.select') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-sorting')" icon="preview-sorting">
|
||||
{{ $t('preview_sorting.preview_sorting_button') }}
|
||||
</MobileActionButton>
|
||||
</template>
|
||||
</FileActionsMobile>
|
||||
|
||||
<EmptyFilePage>
|
||||
<template v-if="$checkPermission('editor')">
|
||||
<h1 class="title">
|
||||
{{ $t('empty_page.title') }}
|
||||
</h1>
|
||||
<p class="description">
|
||||
{{ $t('empty_page.description') }}
|
||||
</p>
|
||||
<ButtonUpload button-style="theme">
|
||||
{{ $t('empty_page.call_to_action') }}
|
||||
</ButtonUpload>
|
||||
</template>
|
||||
<template v-if="$checkPermission('visitor')">
|
||||
<h1 class="title">
|
||||
{{ $t('empty_page.title') }}
|
||||
</h1>
|
||||
</template>
|
||||
</EmptyFilePage>
|
||||
<EmptyFilePage>
|
||||
<template v-if="$checkPermission('editor')">
|
||||
<h1 class="title">
|
||||
{{ $t('empty_page.title') }}
|
||||
</h1>
|
||||
<p class="description">
|
||||
{{ $t('empty_page.description') }}
|
||||
</p>
|
||||
<ButtonUpload button-style="theme">
|
||||
{{ $t('empty_page.call_to_action') }}
|
||||
</ButtonUpload>
|
||||
</template>
|
||||
<template v-if="$checkPermission('visitor')">
|
||||
<h1 class="title">
|
||||
{{ $t('empty_page.title') }}
|
||||
</h1>
|
||||
</template>
|
||||
</EmptyFilePage>
|
||||
|
||||
<FileBrowser />
|
||||
</div>
|
||||
<FileBrowser />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EmptyFilePage from "../../components/FilesView/EmptyFilePage";
|
||||
import FileActionsMobile from "../../components/FilesView/FileActionsMobile";
|
||||
import MobileMultiSelectToolbar from "../../components/FilesView/MobileMultiSelectToolbar";
|
||||
import MobileActionButton from "../../components/FilesView/MobileActionButton";
|
||||
import MobileContextMenu from "../../components/FilesView/MobileContextMenu";
|
||||
import MobileCreateMenu from "../../components/FilesView/MobileCreateMenu";
|
||||
import ToolbarButton from "../../components/FilesView/ToolbarButton";
|
||||
import OptionUpload from "../../components/FilesView/OptionUpload";
|
||||
import ButtonUpload from "../../components/FilesView/ButtonUpload";
|
||||
import FileBrowser from "../../components/FilesView/FileBrowser";
|
||||
import ContextMenu from "../../components/FilesView/ContextMenu";
|
||||
import OptionGroup from "../../components/FilesView/OptionGroup";
|
||||
import Option from "../../components/FilesView/Option";
|
||||
import {events} from "../../bus"
|
||||
import { mapGetters } from 'vuex'
|
||||
import EmptyFilePage from '../../components/FilesView/EmptyFilePage'
|
||||
import FileActionsMobile from '../../components/FilesView/FileActionsMobile'
|
||||
import MobileMultiSelectToolbar from '../../components/FilesView/MobileMultiSelectToolbar'
|
||||
import MobileActionButton from '../../components/FilesView/MobileActionButton'
|
||||
import MobileContextMenu from '../../components/FilesView/MobileContextMenu'
|
||||
import MobileCreateMenu from '../../components/FilesView/MobileCreateMenu'
|
||||
import ToolbarButton from '../../components/FilesView/ToolbarButton'
|
||||
import OptionUpload from '../../components/FilesView/OptionUpload'
|
||||
import ButtonUpload from '../../components/FilesView/ButtonUpload'
|
||||
import FileBrowser from '../../components/FilesView/FileBrowser'
|
||||
import ContextMenu from '../../components/FilesView/ContextMenu'
|
||||
import OptionGroup from '../../components/FilesView/OptionGroup'
|
||||
import Option from '../../components/FilesView/Option'
|
||||
import { events } from '../../bus'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Files',
|
||||
components: {
|
||||
MobileMultiSelectToolbar,
|
||||
MobileActionButton,
|
||||
MobileContextMenu,
|
||||
MobileCreateMenu,
|
||||
ToolbarButton,
|
||||
OptionUpload,
|
||||
ButtonUpload,
|
||||
OptionGroup,
|
||||
FileBrowser,
|
||||
ContextMenu,
|
||||
Option,
|
||||
FileActionsMobile,
|
||||
EmptyFilePage,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'clipboard',
|
||||
])
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
item: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
createFolder() {
|
||||
events.$emit('popup:open', {name: 'create-folder'})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$store.dispatch('getSharedFolder', this.$route.params.id)
|
||||
export default {
|
||||
name: 'Files',
|
||||
components: {
|
||||
MobileMultiSelectToolbar,
|
||||
MobileActionButton,
|
||||
MobileContextMenu,
|
||||
MobileCreateMenu,
|
||||
ToolbarButton,
|
||||
OptionUpload,
|
||||
ButtonUpload,
|
||||
OptionGroup,
|
||||
FileBrowser,
|
||||
ContextMenu,
|
||||
Option,
|
||||
FileActionsMobile,
|
||||
EmptyFilePage,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['clipboard']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
item: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
createFolder() {
|
||||
events.$emit('popup:open', { name: 'create-folder' })
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$store.dispatch('getSharedFolder', this.$route.params.id)
|
||||
|
||||
events.$on('context-menu:show', (event, item) => this.item = item)
|
||||
events.$on('mobile-context-menu:show', item => this.item = item)
|
||||
}
|
||||
}
|
||||
events.$on('context-menu:show', (event, item) => (this.item = item))
|
||||
events.$on('mobile-context-menu:show', (item) => (this.item = item))
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,131 +1,138 @@
|
||||
<template>
|
||||
<div>
|
||||
<ContextMenu>
|
||||
<template v-slot:single-select v-if="item">
|
||||
<OptionGroup>
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$shareFileOrFolder(item)" :title="item.data.relationships.shared ? $t('context_menu.share_edit') : $t('context_menu.share')" icon="share" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$openInDetailPanel(item)" :title="$t('context_menu.detail')" icon="detail" />
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
<div>
|
||||
<ContextMenu>
|
||||
<template v-slot:single-select v-if="item">
|
||||
<OptionGroup>
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option
|
||||
@click.native="$shareFileOrFolder(item)"
|
||||
:title="item.data.relationships.shared ? $t('context_menu.share_edit') : $t('context_menu.share')"
|
||||
icon="share"
|
||||
/>
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$openInDetailPanel(item)" :title="$t('context_menu.detail')" icon="detail" />
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
|
||||
<template v-slot:multiple-select v-if="item">
|
||||
<OptionGroup>
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
</ContextMenu>
|
||||
<template v-slot:multiple-select v-if="item">
|
||||
<OptionGroup>
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
</ContextMenu>
|
||||
|
||||
<MobileContextMenu>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
<Option @click.native="$shareFileOrFolder(item)" :title="item && item.shared ? $t('context_menu.share_edit') : $t('context_menu.share')" icon="share" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</MobileContextMenu>
|
||||
<MobileContextMenu>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
<Option @click.native="$shareFileOrFolder(item)" :title="item && item.shared ? $t('context_menu.share_edit') : $t('context_menu.share')" icon="share" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</MobileContextMenu>
|
||||
|
||||
<FileActionsMobile>
|
||||
<MobileActionButton @click.native="$openSpotlight()" icon="search">
|
||||
{{ $t('Spotlight') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-filter')" :icon="$getCurrentSectionIcon()">
|
||||
{{ $getCurrentSectionName() }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButtonUpload>
|
||||
{{ $t('context_menu.upload') }}
|
||||
</MobileActionButtonUpload>
|
||||
<MobileActionButton @click.native="$enableMultiSelectMode" icon="check-square">
|
||||
{{ $t('context_menu.select') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-sorting')" icon="preview-sorting">
|
||||
{{ $t('preview_sorting.preview_sorting_button') }}
|
||||
</MobileActionButton>
|
||||
</FileActionsMobile>
|
||||
<FileActionsMobile>
|
||||
<MobileActionButton @click.native="$openSpotlight()" icon="search">
|
||||
{{ $t('Spotlight') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-filter')" :icon="$getCurrentSectionIcon()">
|
||||
{{ $getCurrentSectionName() }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButtonUpload>
|
||||
{{ $t('context_menu.upload') }}
|
||||
</MobileActionButtonUpload>
|
||||
<MobileActionButton @click.native="$enableMultiSelectMode" icon="check-square">
|
||||
{{ $t('context_menu.select') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-sorting')" icon="preview-sorting">
|
||||
{{ $t('preview_sorting.preview_sorting_button') }}
|
||||
</MobileActionButton>
|
||||
</FileActionsMobile>
|
||||
|
||||
<EmptyFilePage>
|
||||
<h1 class="title">
|
||||
{{ $t('empty_page.title') }}
|
||||
</h1>
|
||||
<p class="description">
|
||||
{{ $t('empty_page.description') }}
|
||||
</p>
|
||||
<ButtonUpload button-style="theme">
|
||||
{{ $t('empty_page.call_to_action') }}
|
||||
</ButtonUpload>
|
||||
</EmptyFilePage>
|
||||
<EmptyFilePage>
|
||||
<h1 class="title">
|
||||
{{ $t('empty_page.title') }}
|
||||
</h1>
|
||||
<p class="description">
|
||||
{{ $t('empty_page.description') }}
|
||||
</p>
|
||||
<ButtonUpload button-style="theme">
|
||||
{{ $t('empty_page.call_to_action') }}
|
||||
</ButtonUpload>
|
||||
</EmptyFilePage>
|
||||
|
||||
<FileBrowser />
|
||||
<FileBrowser />
|
||||
|
||||
<MobileMultiSelectToolbar>
|
||||
<ToolbarButton @click.native="$deleteFileOrFolder(clipboard)" class="action-btn" source="trash" :class="{'is-inactive' : clipboard.length < 1}" :action="$t('actions.delete')" />
|
||||
<ToolbarButton @click.native="$downloadSelection(item)" class="action-btn" source="download" :action="$t('actions.download')" />
|
||||
</MobileMultiSelectToolbar>
|
||||
</div>
|
||||
<MobileMultiSelectToolbar>
|
||||
<ToolbarButton
|
||||
@click.native="$deleteFileOrFolder(clipboard)"
|
||||
class="action-btn"
|
||||
source="trash"
|
||||
:class="{ 'is-inactive': clipboard.length < 1 }"
|
||||
:action="$t('actions.delete')"
|
||||
/>
|
||||
<ToolbarButton @click.native="$downloadSelection(item)" class="action-btn" source="download" :action="$t('actions.download')" />
|
||||
</MobileMultiSelectToolbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EmptyFilePage from "../../components/FilesView/EmptyFilePage";
|
||||
import FileActionsMobile from "../../components/FilesView/FileActionsMobile";
|
||||
import MobileActionButtonUpload from "../../components/FilesView/MobileActionButtonUpload";
|
||||
import MobileActionButton from "../../components/FilesView/MobileActionButton";
|
||||
import MobileMultiSelectToolbar from "../../components/FilesView/MobileMultiSelectToolbar";
|
||||
import MobileContextMenu from "../../components/FilesView/MobileContextMenu";
|
||||
import ToolbarButton from "../../components/FilesView/ToolbarButton";
|
||||
import ButtonUpload from "../../components/FilesView/ButtonUpload";
|
||||
import FileBrowser from "../../components/FilesView/FileBrowser";
|
||||
import ContextMenu from "../../components/FilesView/ContextMenu";
|
||||
import OptionGroup from "../../components/FilesView/OptionGroup";
|
||||
import Option from "../../components/FilesView/Option";
|
||||
import { mapGetters } from 'vuex'
|
||||
import {events} from "../../bus";
|
||||
import EmptyFilePage from '../../components/FilesView/EmptyFilePage'
|
||||
import FileActionsMobile from '../../components/FilesView/FileActionsMobile'
|
||||
import MobileActionButtonUpload from '../../components/FilesView/MobileActionButtonUpload'
|
||||
import MobileActionButton from '../../components/FilesView/MobileActionButton'
|
||||
import MobileMultiSelectToolbar from '../../components/FilesView/MobileMultiSelectToolbar'
|
||||
import MobileContextMenu from '../../components/FilesView/MobileContextMenu'
|
||||
import ToolbarButton from '../../components/FilesView/ToolbarButton'
|
||||
import ButtonUpload from '../../components/FilesView/ButtonUpload'
|
||||
import FileBrowser from '../../components/FilesView/FileBrowser'
|
||||
import ContextMenu from '../../components/FilesView/ContextMenu'
|
||||
import OptionGroup from '../../components/FilesView/OptionGroup'
|
||||
import Option from '../../components/FilesView/Option'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { events } from '../../bus'
|
||||
|
||||
export default {
|
||||
name: 'RecentUploads',
|
||||
components: {
|
||||
MobileActionButtonUpload,
|
||||
MobileMultiSelectToolbar,
|
||||
MobileActionButton,
|
||||
MobileContextMenu,
|
||||
ToolbarButton,
|
||||
ButtonUpload,
|
||||
OptionGroup,
|
||||
FileBrowser,
|
||||
ContextMenu,
|
||||
Option,
|
||||
FileActionsMobile,
|
||||
EmptyFilePage,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'clipboard',
|
||||
'user',
|
||||
]),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
item: undefined,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$store.dispatch('getRecentUploads')
|
||||
export default {
|
||||
name: 'RecentUploads',
|
||||
components: {
|
||||
MobileActionButtonUpload,
|
||||
MobileMultiSelectToolbar,
|
||||
MobileActionButton,
|
||||
MobileContextMenu,
|
||||
ToolbarButton,
|
||||
ButtonUpload,
|
||||
OptionGroup,
|
||||
FileBrowser,
|
||||
ContextMenu,
|
||||
Option,
|
||||
FileActionsMobile,
|
||||
EmptyFilePage,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['clipboard', 'user']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
item: undefined,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$store.dispatch('getRecentUploads')
|
||||
|
||||
events.$on('context-menu:show', (event, item) => this.item = item)
|
||||
events.$on('mobile-context-menu:show', item => this.item = item)
|
||||
}
|
||||
}
|
||||
events.$on('context-menu:show', (event, item) => (this.item = item))
|
||||
events.$on('mobile-context-menu:show', (item) => (this.item = item))
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,240 +1,244 @@
|
||||
<template>
|
||||
<div>
|
||||
<MobileContextMenu>
|
||||
<OptionGroup v-if="canEdit && item">
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<div>
|
||||
<MobileContextMenu>
|
||||
<OptionGroup v-if="canEdit && item">
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup v-if="item">
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</MobileContextMenu>
|
||||
</MobileContextMenu>
|
||||
|
||||
<MobileCreateMenu>
|
||||
<OptionGroup>
|
||||
<OptionUpload :title="$t('actions.upload')" type="file" :is-hover-disabled="true" />
|
||||
<OptionUpload :title="$t('actions.upload_folder')" type="folder" :is-hover-disabled="true" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.stop.native="createFolder" :title="$t('actions.create_folder')" icon="folder-plus" :is-hover-disabled="true" />
|
||||
</OptionGroup>
|
||||
</MobileCreateMenu>
|
||||
<MobileCreateMenu>
|
||||
<OptionGroup>
|
||||
<OptionUpload :title="$t('actions.upload')" type="file" :is-hover-disabled="true" />
|
||||
<OptionUpload :title="$t('actions.upload_folder')" type="folder" :is-hover-disabled="true" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.stop.native="createFolder" :title="$t('actions.create_folder')" icon="folder-plus" :is-hover-disabled="true" />
|
||||
</OptionGroup>
|
||||
</MobileCreateMenu>
|
||||
|
||||
<MobileTeamContextMenu>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$detachMeFromTeamFolder(teamFolder)" :title="$t('Leave the Team Folder')" icon="user-minus" />
|
||||
</OptionGroup>
|
||||
</MobileTeamContextMenu>
|
||||
<MobileTeamContextMenu>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$detachMeFromTeamFolder(teamFolder)" :title="$t('Leave the Team Folder')" icon="user-minus" />
|
||||
</OptionGroup>
|
||||
</MobileTeamContextMenu>
|
||||
|
||||
<MobileMultiSelectToolbar>
|
||||
<ToolbarButton v-if="canEdit" @click.native="$moveFileOrFolder(clipboard)" class="action-btn" source="move" :action="$t('actions.move')" :class="{'is-inactive' : clipboard.length < 1}" />
|
||||
<ToolbarButton v-if="canEdit" @click.native="$deleteFileOrFolder(clipboard)" class="action-btn" source="trash" :class="{'is-inactive' : clipboard.length < 1}" :action="$t('actions.delete')" />
|
||||
<MobileMultiSelectToolbar>
|
||||
<ToolbarButton
|
||||
v-if="canEdit"
|
||||
@click.native="$moveFileOrFolder(clipboard)"
|
||||
class="action-btn"
|
||||
source="move"
|
||||
:action="$t('actions.move')"
|
||||
:class="{ 'is-inactive': clipboard.length < 1 }"
|
||||
/>
|
||||
<ToolbarButton
|
||||
v-if="canEdit"
|
||||
@click.native="$deleteFileOrFolder(clipboard)"
|
||||
class="action-btn"
|
||||
source="trash"
|
||||
:class="{ 'is-inactive': clipboard.length < 1 }"
|
||||
:action="$t('actions.delete')"
|
||||
/>
|
||||
<ToolbarButton @click.native="$downloadSelection(item)" class="action-btn" source="download" :action="$t('actions.download')" />
|
||||
</MobileMultiSelectToolbar>
|
||||
</MobileMultiSelectToolbar>
|
||||
|
||||
<ContextMenu>
|
||||
<template v-slot:empty-select v-if="canEdit">
|
||||
<OptionGroup v-if="! isTeamFolderHomepage">
|
||||
<OptionUpload :title="$t('actions.upload')" type="file" />
|
||||
<OptionUpload :title="$t('actions.upload_folder')" type="folder" />
|
||||
</OptionGroup>
|
||||
<OptionGroup v-if="! isTeamFolderHomepage">
|
||||
<Option @click.stop.native="$createFolder" :title="$t('actions.create_folder')" icon="folder-plus" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
<ContextMenu>
|
||||
<template v-slot:empty-select v-if="canEdit">
|
||||
<OptionGroup v-if="!isTeamFolderHomepage">
|
||||
<OptionUpload :title="$t('actions.upload')" type="file" />
|
||||
<OptionUpload :title="$t('actions.upload_folder')" type="folder" />
|
||||
</OptionGroup>
|
||||
<OptionGroup v-if="!isTeamFolderHomepage">
|
||||
<Option @click.stop.native="$createFolder" :title="$t('actions.create_folder')" icon="folder-plus" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
|
||||
<template v-slot:single-select v-if="item">
|
||||
<OptionGroup v-if="canEdit">
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$openInDetailPanel(item)" :title="$t('context_menu.detail')" icon="detail" />
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
<template v-slot:single-select v-if="item">
|
||||
<OptionGroup v-if="canEdit">
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$openInDetailPanel(item)" :title="$t('context_menu.detail')" icon="detail" />
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
|
||||
<template v-slot:multiple-select v-if="item">
|
||||
<OptionGroup v-if="canEdit">
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
</ContextMenu>
|
||||
<template v-slot:multiple-select v-if="item">
|
||||
<OptionGroup v-if="canEdit">
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
</ContextMenu>
|
||||
|
||||
<FileActionsMobile>
|
||||
<MobileActionButton @click.native="$openSpotlight()" icon="search">
|
||||
{{ $t('Spotlight') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-filter')" :icon="$getCurrentSectionIcon()">
|
||||
{{ $getCurrentSectionName() }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton v-if="canEdit" @click.native="$showMobileMenu('create-list')" icon="cloud-plus">
|
||||
{{ $t('mobile.create') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$enableMultiSelectMode" icon="check-square">
|
||||
{{ $t('context_menu.select') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-sorting')" icon="preview-sorting">
|
||||
{{ $t('preview_sorting.preview_sorting_button') }}
|
||||
</MobileActionButton>
|
||||
</FileActionsMobile>
|
||||
<FileActionsMobile>
|
||||
<MobileActionButton @click.native="$openSpotlight()" icon="search">
|
||||
{{ $t('Spotlight') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-filter')" :icon="$getCurrentSectionIcon()">
|
||||
{{ $getCurrentSectionName() }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton v-if="canEdit" @click.native="$showMobileMenu('create-list')" icon="cloud-plus">
|
||||
{{ $t('mobile.create') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$enableMultiSelectMode" icon="check-square">
|
||||
{{ $t('context_menu.select') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-sorting')" icon="preview-sorting">
|
||||
{{ $t('preview_sorting.preview_sorting_button') }}
|
||||
</MobileActionButton>
|
||||
</FileActionsMobile>
|
||||
|
||||
<EmptyFilePage>
|
||||
<EmptyFilePage>
|
||||
<!--Homepage-->
|
||||
<template v-if="isTeamFolderHomepage">
|
||||
<h1 class="title">
|
||||
{{ $t('Nothing Shared With You') }}
|
||||
</h1>
|
||||
<p class="description">
|
||||
{{ $t('All items that are shared with you will be visible here.') }}
|
||||
</p>
|
||||
</template>
|
||||
|
||||
<!--Homepage-->
|
||||
<template v-if="isTeamFolderHomepage">
|
||||
<h1 class="title">
|
||||
{{ $t('Nothing Shared With You') }}
|
||||
</h1>
|
||||
<p class="description">
|
||||
{{ $t('All items that are shared with you will be visible here.') }}
|
||||
</p>
|
||||
</template>
|
||||
<!--Empty folder wit can-edit privileges -->
|
||||
<template v-if="canEdit && !isTeamFolderHomepage">
|
||||
<h1 class="title">
|
||||
{{ $t('empty_page.title') }}
|
||||
</h1>
|
||||
<p class="description">
|
||||
{{ $t('empty_page.description') }}
|
||||
</p>
|
||||
<ButtonUpload button-style="theme">
|
||||
{{ $t('empty_page.call_to_action') }}
|
||||
</ButtonUpload>
|
||||
</template>
|
||||
|
||||
<!--Empty folder wit can-edit privileges -->
|
||||
<template v-if="canEdit && ! isTeamFolderHomepage">
|
||||
<h1 class="title">
|
||||
{{ $t('empty_page.title') }}
|
||||
</h1>
|
||||
<p class="description">
|
||||
{{ $t('empty_page.description') }}
|
||||
</p>
|
||||
<ButtonUpload button-style="theme">
|
||||
{{ $t('empty_page.call_to_action') }}
|
||||
</ButtonUpload>
|
||||
</template>
|
||||
<!--Empty folder wit can-view privileges -->
|
||||
<template v-if="!canEdit && !isTeamFolderHomepage">
|
||||
<h1 class="title">
|
||||
{{ $t('There is Nothing Yet') }}
|
||||
</h1>
|
||||
</template>
|
||||
</EmptyFilePage>
|
||||
|
||||
<!--Empty folder wit can-view privileges -->
|
||||
<template v-if="! canEdit && ! isTeamFolderHomepage">
|
||||
<h1 class="title">
|
||||
{{ $t('There is Nothing Yet') }}
|
||||
</h1>
|
||||
</template>
|
||||
</EmptyFilePage>
|
||||
|
||||
<FileBrowser />
|
||||
</div>
|
||||
<FileBrowser />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MobileTeamContextMenu from "../../components/FilesView/MobileTeamContextMenu";
|
||||
import EmptyFilePage from "../../components/FilesView/EmptyFilePage";
|
||||
import FileActionsMobile from "../../components/FilesView/FileActionsMobile";
|
||||
import MobileActionButtonUpload from "../../components/FilesView/MobileActionButtonUpload";
|
||||
import MobileMultiSelectToolbar from "../../components/FilesView/MobileMultiSelectToolbar";
|
||||
import MobileActionButton from "../../components/FilesView/MobileActionButton";
|
||||
import MobileContextMenu from "../../components/FilesView/MobileContextMenu";
|
||||
import MobileCreateMenu from "../../components/FilesView/MobileCreateMenu";
|
||||
import ButtonUpload from "../../components/FilesView/ButtonUpload";
|
||||
import ToolbarButton from "../../components/FilesView/ToolbarButton";
|
||||
import OptionUpload from "../../components/FilesView/OptionUpload";
|
||||
import FileBrowser from "../../components/FilesView/FileBrowser";
|
||||
import ContextMenu from "../../components/FilesView/ContextMenu";
|
||||
import OptionGroup from "../../components/FilesView/OptionGroup";
|
||||
import ButtonBase from "../../components/FilesView/ButtonBase";
|
||||
import Option from "../../components/FilesView/Option";
|
||||
import { mapGetters } from 'vuex'
|
||||
import {events} from "../../bus";
|
||||
import MobileTeamContextMenu from '../../components/FilesView/MobileTeamContextMenu'
|
||||
import EmptyFilePage from '../../components/FilesView/EmptyFilePage'
|
||||
import FileActionsMobile from '../../components/FilesView/FileActionsMobile'
|
||||
import MobileActionButtonUpload from '../../components/FilesView/MobileActionButtonUpload'
|
||||
import MobileMultiSelectToolbar from '../../components/FilesView/MobileMultiSelectToolbar'
|
||||
import MobileActionButton from '../../components/FilesView/MobileActionButton'
|
||||
import MobileContextMenu from '../../components/FilesView/MobileContextMenu'
|
||||
import MobileCreateMenu from '../../components/FilesView/MobileCreateMenu'
|
||||
import ButtonUpload from '../../components/FilesView/ButtonUpload'
|
||||
import ToolbarButton from '../../components/FilesView/ToolbarButton'
|
||||
import OptionUpload from '../../components/FilesView/OptionUpload'
|
||||
import FileBrowser from '../../components/FilesView/FileBrowser'
|
||||
import ContextMenu from '../../components/FilesView/ContextMenu'
|
||||
import OptionGroup from '../../components/FilesView/OptionGroup'
|
||||
import ButtonBase from '../../components/FilesView/ButtonBase'
|
||||
import Option from '../../components/FilesView/Option'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { events } from '../../bus'
|
||||
|
||||
export default {
|
||||
name: 'SharedWithMe',
|
||||
components: {
|
||||
MobileActionButtonUpload,
|
||||
MobileMultiSelectToolbar,
|
||||
MobileTeamContextMenu,
|
||||
MobileActionButton,
|
||||
MobileContextMenu,
|
||||
MobileCreateMenu,
|
||||
ToolbarButton,
|
||||
ButtonUpload,
|
||||
OptionUpload,
|
||||
OptionGroup,
|
||||
FileBrowser,
|
||||
ContextMenu,
|
||||
ButtonBase,
|
||||
Option,
|
||||
FileActionsMobile,
|
||||
EmptyFilePage,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'currentTeamFolder',
|
||||
'clipboard',
|
||||
'config',
|
||||
'user',
|
||||
]),
|
||||
teamFolder() {
|
||||
return this.currentTeamFolder
|
||||
? this.currentTeamFolder
|
||||
: this.clipboard[0]
|
||||
},
|
||||
canEdit() {
|
||||
if (this.currentTeamFolder && this.user) {
|
||||
let member = this.currentTeamFolder.data.relationships.members.data.find(member => member.data.id === this.user.data.id)
|
||||
export default {
|
||||
name: 'SharedWithMe',
|
||||
components: {
|
||||
MobileActionButtonUpload,
|
||||
MobileMultiSelectToolbar,
|
||||
MobileTeamContextMenu,
|
||||
MobileActionButton,
|
||||
MobileContextMenu,
|
||||
MobileCreateMenu,
|
||||
ToolbarButton,
|
||||
ButtonUpload,
|
||||
OptionUpload,
|
||||
OptionGroup,
|
||||
FileBrowser,
|
||||
ContextMenu,
|
||||
ButtonBase,
|
||||
Option,
|
||||
FileActionsMobile,
|
||||
EmptyFilePage,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['currentTeamFolder', 'clipboard', 'config', 'user']),
|
||||
teamFolder() {
|
||||
return this.currentTeamFolder ? this.currentTeamFolder : this.clipboard[0]
|
||||
},
|
||||
canEdit() {
|
||||
if (this.currentTeamFolder && this.user) {
|
||||
let member = this.currentTeamFolder.data.relationships.members.data.find((member) => member.data.id === this.user.data.id)
|
||||
|
||||
return member.data.attributes.permission === 'can-edit'
|
||||
}
|
||||
return member.data.attributes.permission === 'can-edit'
|
||||
}
|
||||
|
||||
return false
|
||||
},
|
||||
isTeamFolderHomepage() {
|
||||
return this.$isThisRoute(this.$route, ['SharedWithMe'])
|
||||
&& ! this.$route.params.id
|
||||
},
|
||||
isFolder() {
|
||||
return this.item && this.item.data.type === 'folder'
|
||||
},
|
||||
hasFile() {
|
||||
return this.clipboard.find(item => item.type !== 'folder')
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
item: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
createFolder() {
|
||||
events.$emit('popup:open', {name: 'create-folder'})
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$store.commit('SET_CURRENT_TEAM_FOLDER', undefined)
|
||||
this.$store.dispatch('getSharedWithMeFolder', this.$route.params.id)
|
||||
return false
|
||||
},
|
||||
isTeamFolderHomepage() {
|
||||
return this.$isThisRoute(this.$route, ['SharedWithMe']) && !this.$route.params.id
|
||||
},
|
||||
isFolder() {
|
||||
return this.item && this.item.data.type === 'folder'
|
||||
},
|
||||
hasFile() {
|
||||
return this.clipboard.find((item) => item.type !== 'folder')
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
item: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
createFolder() {
|
||||
events.$emit('popup:open', { name: 'create-folder' })
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$store.commit('SET_CURRENT_TEAM_FOLDER', undefined)
|
||||
this.$store.dispatch('getSharedWithMeFolder', this.$route.params.id)
|
||||
|
||||
events.$on('context-menu:show', (event, item) => this.item = item)
|
||||
events.$on('mobile-context-menu:show', item => this.item = item)
|
||||
events.$on('context-menu:current-folder', folder => this.item = folder)
|
||||
events.$on('context-menu:show', (event, item) => (this.item = item))
|
||||
events.$on('mobile-context-menu:show', (item) => (this.item = item))
|
||||
events.$on('context-menu:current-folder', (folder) => (this.item = folder))
|
||||
|
||||
events.$on('action:confirmed', data => {
|
||||
events.$on('action:confirmed', (data) => {
|
||||
// Leave team folder after popup confirmation
|
||||
if (data.operation === 'leave-team-folder')
|
||||
axios
|
||||
.delete(`/api/teams/folders/${data.id}/leave`)
|
||||
.then(() => {
|
||||
if (this.$route.params.id) {
|
||||
this.$router.push({ name: 'SharedWithMe' })
|
||||
} else {
|
||||
this.$store.dispatch('getSharedWithMeFolder', undefined)
|
||||
}
|
||||
|
||||
// Leave team folder after popup confirmation
|
||||
if (data.operation === 'leave-team-folder')
|
||||
axios.delete(`/api/teams/folders/${data.id}/leave`)
|
||||
.then(() => {
|
||||
|
||||
if (this.$route.params.id) {
|
||||
this.$router.push({name: 'SharedWithMe'})
|
||||
} else {
|
||||
this.$store.dispatch('getSharedWithMeFolder', undefined)
|
||||
}
|
||||
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('You have successfully left the team folder'),
|
||||
})
|
||||
})
|
||||
.catch(() => this.$isSomethingWrong())
|
||||
})
|
||||
},
|
||||
destroyed() {
|
||||
events.$off('action:confirmed')
|
||||
},
|
||||
}
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('You have successfully left the team folder'),
|
||||
})
|
||||
})
|
||||
.catch(() => this.$isSomethingWrong())
|
||||
})
|
||||
},
|
||||
destroyed() {
|
||||
events.$off('action:confirmed')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,265 +1,285 @@
|
||||
<template>
|
||||
<div>
|
||||
<MobileContextMenu>
|
||||
<OptionGroup v-if="item && isFolder">
|
||||
<Option @click.native="addToFavourites" :title="isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites')" icon="favourites" />
|
||||
<div>
|
||||
<MobileContextMenu>
|
||||
<OptionGroup v-if="item && isFolder">
|
||||
<Option
|
||||
@click.native="addToFavourites"
|
||||
:title="isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites')"
|
||||
icon="favourites"
|
||||
/>
|
||||
</OptionGroup>
|
||||
|
||||
<OptionGroup v-if="item">
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup v-if="item">
|
||||
<Option @click.native="$shareFileOrFolder(item)" :title="item.data.relationships.shared ? $t('context_menu.share_edit') : $t('context_menu.share')" icon="share" />
|
||||
<Option @click.native="$updateTeamFolder(item)" v-if="isFolder" :title="$t('Edit Team Members')" icon="users" />
|
||||
</OptionGroup>
|
||||
<OptionGroup v-if="item">
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup v-if="item">
|
||||
<Option @click.native="$shareFileOrFolder(item)" :title="item.data.relationships.shared ? $t('context_menu.share_edit') : $t('context_menu.share')" icon="share" />
|
||||
<Option @click.native="$updateTeamFolder(item)" v-if="isFolder" :title="$t('Edit Team Members')" icon="users" />
|
||||
</OptionGroup>
|
||||
|
||||
<OptionGroup v-if="item">
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</MobileContextMenu>
|
||||
</MobileContextMenu>
|
||||
|
||||
<MobileCreateMenu>
|
||||
<OptionGroup>
|
||||
<OptionUpload :title="$t('actions.upload')" type="file" :is-hover-disabled="true" />
|
||||
<OptionUpload :title="$t('actions.upload_folder')" type="folder" :is-hover-disabled="true" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.stop.native="$createTeamFolder" :title="$t('Create Team Folder')" icon="users" :is-hover-disabled="true" />
|
||||
<Option @click.stop.native="createFolder" :title="$t('actions.create_folder')" icon="folder-plus" :is-hover-disabled="true" />
|
||||
</OptionGroup>
|
||||
</MobileCreateMenu>
|
||||
<MobileCreateMenu>
|
||||
<OptionGroup>
|
||||
<OptionUpload :title="$t('actions.upload')" type="file" :is-hover-disabled="true" />
|
||||
<OptionUpload :title="$t('actions.upload_folder')" type="folder" :is-hover-disabled="true" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.stop.native="$createTeamFolder" :title="$t('Create Team Folder')" icon="users" :is-hover-disabled="true" />
|
||||
<Option @click.stop.native="createFolder" :title="$t('actions.create_folder')" icon="folder-plus" :is-hover-disabled="true" />
|
||||
</OptionGroup>
|
||||
</MobileCreateMenu>
|
||||
|
||||
<MobileTeamContextMenu>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$updateTeamFolder(teamFolder)" :title="$t('Edit Members')" icon="rename" />
|
||||
<Option @click.native="$dissolveTeamFolder(teamFolder)" :title="$t('Dissolve Team')" icon="trash" />
|
||||
</OptionGroup>
|
||||
</MobileTeamContextMenu>
|
||||
<MobileTeamContextMenu>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$updateTeamFolder(teamFolder)" :title="$t('Edit Members')" icon="rename" />
|
||||
<Option @click.native="$dissolveTeamFolder(teamFolder)" :title="$t('Dissolve Team')" icon="trash" />
|
||||
</OptionGroup>
|
||||
</MobileTeamContextMenu>
|
||||
|
||||
<MobileMultiSelectToolbar>
|
||||
<ToolbarButton @click.native="$moveFileOrFolder(clipboard)" class="action-btn" source="move" :action="$t('actions.move')" :class="{'is-inactive' : clipboard.length < 1}" />
|
||||
<ToolbarButton @click.native="$deleteFileOrFolder(clipboard)" class="action-btn" source="trash" :class="{'is-inactive' : clipboard.length < 1}" :action="$t('actions.delete')" />
|
||||
<MobileMultiSelectToolbar>
|
||||
<ToolbarButton
|
||||
@click.native="$moveFileOrFolder(clipboard)"
|
||||
class="action-btn"
|
||||
source="move"
|
||||
:action="$t('actions.move')"
|
||||
:class="{ 'is-inactive': clipboard.length < 1 }"
|
||||
/>
|
||||
<ToolbarButton
|
||||
@click.native="$deleteFileOrFolder(clipboard)"
|
||||
class="action-btn"
|
||||
source="trash"
|
||||
:class="{ 'is-inactive': clipboard.length < 1 }"
|
||||
:action="$t('actions.delete')"
|
||||
/>
|
||||
<ToolbarButton @click.native="$downloadSelection(item)" class="action-btn" source="download" :action="$t('actions.download')" />
|
||||
</MobileMultiSelectToolbar>
|
||||
</MobileMultiSelectToolbar>
|
||||
|
||||
<ContextMenu>
|
||||
<template v-slot:empty-select>
|
||||
<OptionGroup v-if="! isTeamFolderHomepage">
|
||||
<OptionUpload :title="$t('actions.upload')" type="file" />
|
||||
<OptionUpload :title="$t('actions.upload_folder')" type="folder" />
|
||||
<Option @click.stop.native="$createFolder" :title="$t('actions.create_folder')" icon="folder-plus" />
|
||||
</OptionGroup>
|
||||
<OptionGroup v-if="isTeamFolderHomepage">
|
||||
<Option @click.native="$createTeamFolder" :title="$t('Create Team Folder')" icon="users" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
<ContextMenu>
|
||||
<template v-slot:empty-select>
|
||||
<OptionGroup v-if="!isTeamFolderHomepage">
|
||||
<OptionUpload :title="$t('actions.upload')" type="file" />
|
||||
<OptionUpload :title="$t('actions.upload_folder')" type="folder" />
|
||||
<Option @click.stop.native="$createFolder" :title="$t('actions.create_folder')" icon="folder-plus" />
|
||||
</OptionGroup>
|
||||
<OptionGroup v-if="isTeamFolderHomepage">
|
||||
<Option @click.native="$createTeamFolder" :title="$t('Create Team Folder')" icon="users" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
|
||||
<template v-slot:single-select v-if="item">
|
||||
<OptionGroup v-if="isFolder">
|
||||
<Option @click.native="addToFavourites" :title="isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites')" icon="favourites" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$shareFileOrFolder(item)" :title="item.data.relationships.shared ? $t('context_menu.share_edit') : $t('context_menu.share')" icon="share" />
|
||||
<Option @click.native="$updateTeamFolder(item)" v-if="isFolder" :title="$t('Edit Team Members')" icon="users" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$openInDetailPanel(item)" :title="$t('context_menu.detail')" icon="detail" />
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
<template v-slot:single-select v-if="item">
|
||||
<OptionGroup v-if="isFolder">
|
||||
<Option
|
||||
@click.native="addToFavourites"
|
||||
:title="isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites')"
|
||||
icon="favourites"
|
||||
/>
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$renameFileOrFolder(item)" :title="$t('context_menu.rename')" icon="rename" />
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option
|
||||
@click.native="$shareFileOrFolder(item)"
|
||||
:title="item.data.relationships.shared ? $t('context_menu.share_edit') : $t('context_menu.share')"
|
||||
icon="share"
|
||||
/>
|
||||
<Option @click.native="$updateTeamFolder(item)" v-if="isFolder" :title="$t('Edit Team Members')" icon="users" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$openInDetailPanel(item)" :title="$t('context_menu.detail')" icon="detail" />
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
|
||||
<template v-slot:multiple-select v-if="item">
|
||||
<OptionGroup v-if="!hasFile">
|
||||
<Option @click.native="addToFavourites" :title="isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites')" icon="favourites" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
</ContextMenu>
|
||||
<template v-slot:multiple-select v-if="item">
|
||||
<OptionGroup v-if="!hasFile">
|
||||
<Option
|
||||
@click.native="addToFavourites"
|
||||
:title="isInFavourites ? $t('context_menu.remove_from_favourites') : $t('context_menu.add_to_favourites')"
|
||||
icon="favourites"
|
||||
/>
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$moveFileOrFolder(item)" :title="$t('context_menu.move')" icon="move-item" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
</ContextMenu>
|
||||
|
||||
<FileActionsMobile>
|
||||
<MobileActionButton @click.native="$openSpotlight()" icon="search">
|
||||
{{ $t('Spotlight') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-filter')" :icon="$getCurrentSectionIcon()">
|
||||
{{ $getCurrentSectionName() }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('create-list')" v-if="$checkPermission(['master', 'editor'])" icon="cloud-plus">
|
||||
{{ $t('mobile.create') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$enableMultiSelectMode" icon="check-square">
|
||||
{{ $t('context_menu.select') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-sorting')" icon="preview-sorting">
|
||||
{{ $t('preview_sorting.preview_sorting_button') }}
|
||||
</MobileActionButton>
|
||||
</FileActionsMobile>
|
||||
<FileActionsMobile>
|
||||
<MobileActionButton @click.native="$openSpotlight()" icon="search">
|
||||
{{ $t('Spotlight') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-filter')" :icon="$getCurrentSectionIcon()">
|
||||
{{ $getCurrentSectionName() }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('create-list')" v-if="$checkPermission(['master', 'editor'])" icon="cloud-plus">
|
||||
{{ $t('mobile.create') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$enableMultiSelectMode" icon="check-square">
|
||||
{{ $t('context_menu.select') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-sorting')" icon="preview-sorting">
|
||||
{{ $t('preview_sorting.preview_sorting_button') }}
|
||||
</MobileActionButton>
|
||||
</FileActionsMobile>
|
||||
|
||||
<EmptyFilePage>
|
||||
<template v-if="isTeamFolderHomepage">
|
||||
<h1 class="title">
|
||||
{{ $t('Create your Team Folder') }}
|
||||
</h1>
|
||||
<p class="description">
|
||||
{{ $t('Collaborate on your files with your team easily by creating new team folder.') }}
|
||||
</p>
|
||||
<ButtonBase @click.native="$createTeamFolder" button-style="theme" class="m-center">
|
||||
{{ $t('Create Team Folder') }}
|
||||
</ButtonBase>
|
||||
</template>
|
||||
<EmptyFilePage>
|
||||
<template v-if="isTeamFolderHomepage">
|
||||
<h1 class="title">
|
||||
{{ $t('Create your Team Folder') }}
|
||||
</h1>
|
||||
<p class="description">
|
||||
{{ $t('Collaborate on your files with your team easily by creating new team folder.') }}
|
||||
</p>
|
||||
<ButtonBase @click.native="$createTeamFolder" button-style="theme" class="m-center">
|
||||
{{ $t('Create Team Folder') }}
|
||||
</ButtonBase>
|
||||
</template>
|
||||
|
||||
<template v-if="! isTeamFolderHomepage">
|
||||
<h1 class="title">
|
||||
{{ $t('empty_page.title') }}
|
||||
</h1>
|
||||
<p class="description">
|
||||
{{ $t('empty_page.description') }}
|
||||
</p>
|
||||
<ButtonUpload button-style="theme">
|
||||
{{ $t('empty_page.call_to_action') }}
|
||||
</ButtonUpload>
|
||||
</template>
|
||||
</EmptyFilePage>
|
||||
<template v-if="!isTeamFolderHomepage">
|
||||
<h1 class="title">
|
||||
{{ $t('empty_page.title') }}
|
||||
</h1>
|
||||
<p class="description">
|
||||
{{ $t('empty_page.description') }}
|
||||
</p>
|
||||
<ButtonUpload button-style="theme">
|
||||
{{ $t('empty_page.call_to_action') }}
|
||||
</ButtonUpload>
|
||||
</template>
|
||||
</EmptyFilePage>
|
||||
|
||||
<FileBrowser />
|
||||
</div>
|
||||
<FileBrowser />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MobileTeamContextMenu from "../../components/FilesView/MobileTeamContextMenu";
|
||||
import EmptyFilePage from "../../components/FilesView/EmptyFilePage";
|
||||
import FileActionsMobile from "../../components/FilesView/FileActionsMobile";
|
||||
import MobileActionButtonUpload from "../../components/FilesView/MobileActionButtonUpload";
|
||||
import MobileMultiSelectToolbar from "../../components/FilesView/MobileMultiSelectToolbar";
|
||||
import MobileActionButton from "../../components/FilesView/MobileActionButton";
|
||||
import MobileContextMenu from "../../components/FilesView/MobileContextMenu";
|
||||
import MobileCreateMenu from "../../components/FilesView/MobileCreateMenu";
|
||||
import ButtonUpload from "../../components/FilesView/ButtonUpload";
|
||||
import ToolbarButton from "../../components/FilesView/ToolbarButton";
|
||||
import OptionUpload from "../../components/FilesView/OptionUpload";
|
||||
import FileBrowser from "../../components/FilesView/FileBrowser";
|
||||
import ContextMenu from "../../components/FilesView/ContextMenu";
|
||||
import OptionGroup from "../../components/FilesView/OptionGroup";
|
||||
import ButtonBase from "../../components/FilesView/ButtonBase";
|
||||
import Option from "../../components/FilesView/Option";
|
||||
import { mapGetters } from 'vuex'
|
||||
import {events} from "../../bus";
|
||||
import MobileTeamContextMenu from '../../components/FilesView/MobileTeamContextMenu'
|
||||
import EmptyFilePage from '../../components/FilesView/EmptyFilePage'
|
||||
import FileActionsMobile from '../../components/FilesView/FileActionsMobile'
|
||||
import MobileActionButtonUpload from '../../components/FilesView/MobileActionButtonUpload'
|
||||
import MobileMultiSelectToolbar from '../../components/FilesView/MobileMultiSelectToolbar'
|
||||
import MobileActionButton from '../../components/FilesView/MobileActionButton'
|
||||
import MobileContextMenu from '../../components/FilesView/MobileContextMenu'
|
||||
import MobileCreateMenu from '../../components/FilesView/MobileCreateMenu'
|
||||
import ButtonUpload from '../../components/FilesView/ButtonUpload'
|
||||
import ToolbarButton from '../../components/FilesView/ToolbarButton'
|
||||
import OptionUpload from '../../components/FilesView/OptionUpload'
|
||||
import FileBrowser from '../../components/FilesView/FileBrowser'
|
||||
import ContextMenu from '../../components/FilesView/ContextMenu'
|
||||
import OptionGroup from '../../components/FilesView/OptionGroup'
|
||||
import ButtonBase from '../../components/FilesView/ButtonBase'
|
||||
import Option from '../../components/FilesView/Option'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { events } from '../../bus'
|
||||
|
||||
export default {
|
||||
name: 'TeamFolders',
|
||||
components: {
|
||||
MobileActionButtonUpload,
|
||||
MobileMultiSelectToolbar,
|
||||
MobileTeamContextMenu,
|
||||
MobileActionButton,
|
||||
MobileContextMenu,
|
||||
MobileCreateMenu,
|
||||
ToolbarButton,
|
||||
ButtonUpload,
|
||||
OptionUpload,
|
||||
OptionGroup,
|
||||
FileBrowser,
|
||||
ContextMenu,
|
||||
ButtonBase,
|
||||
Option,
|
||||
FileActionsMobile,
|
||||
EmptyFilePage,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'currentTeamFolder',
|
||||
'clipboard',
|
||||
'config',
|
||||
'user',
|
||||
]),
|
||||
teamFolder() {
|
||||
return this.currentTeamFolder
|
||||
? this.currentTeamFolder
|
||||
: this.clipboard[0]
|
||||
},
|
||||
isTeamFolderHomepage() {
|
||||
return this.$isThisRoute(this.$route, ['TeamFolders'])
|
||||
&& ! this.$route.params.id
|
||||
},
|
||||
isFolder() {
|
||||
return this.item && this.item.data.type === 'folder'
|
||||
},
|
||||
isInFavourites() {
|
||||
return this.favourites.find((el) => el.id === this.item.id)
|
||||
},
|
||||
hasFile() {
|
||||
return this.clipboard.find(item => item.type !== 'folder')
|
||||
},
|
||||
favourites() {
|
||||
return this.user.data.relationships.favourites.data
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
item: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addToFavourites() {
|
||||
// Check if folder is in favourites and then add/remove from favourites
|
||||
if (this.favourites && !this.favourites.find(el => el.id === this.item.data.id)) {
|
||||
// Add to favourite folder that is not selected
|
||||
if (!this.clipboard.includes(this.item)) {
|
||||
this.$store.dispatch('addToFavourites', this.item)
|
||||
}
|
||||
export default {
|
||||
name: 'TeamFolders',
|
||||
components: {
|
||||
MobileActionButtonUpload,
|
||||
MobileMultiSelectToolbar,
|
||||
MobileTeamContextMenu,
|
||||
MobileActionButton,
|
||||
MobileContextMenu,
|
||||
MobileCreateMenu,
|
||||
ToolbarButton,
|
||||
ButtonUpload,
|
||||
OptionUpload,
|
||||
OptionGroup,
|
||||
FileBrowser,
|
||||
ContextMenu,
|
||||
ButtonBase,
|
||||
Option,
|
||||
FileActionsMobile,
|
||||
EmptyFilePage,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['currentTeamFolder', 'clipboard', 'config', 'user']),
|
||||
teamFolder() {
|
||||
return this.currentTeamFolder ? this.currentTeamFolder : this.clipboard[0]
|
||||
},
|
||||
isTeamFolderHomepage() {
|
||||
return this.$isThisRoute(this.$route, ['TeamFolders']) && !this.$route.params.id
|
||||
},
|
||||
isFolder() {
|
||||
return this.item && this.item.data.type === 'folder'
|
||||
},
|
||||
isInFavourites() {
|
||||
return this.favourites.find((el) => el.id === this.item.id)
|
||||
},
|
||||
hasFile() {
|
||||
return this.clipboard.find((item) => item.type !== 'folder')
|
||||
},
|
||||
favourites() {
|
||||
return this.user.data.relationships.favourites.data
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
item: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addToFavourites() {
|
||||
// Check if folder is in favourites and then add/remove from favourites
|
||||
if (this.favourites && !this.favourites.find((el) => el.id === this.item.data.id)) {
|
||||
// Add to favourite folder that is not selected
|
||||
if (!this.clipboard.includes(this.item)) {
|
||||
this.$store.dispatch('addToFavourites', this.item)
|
||||
}
|
||||
|
||||
// Add to favourites all selected folders
|
||||
if (this.clipboard.includes(this.item)) {
|
||||
this.$store.dispatch('addToFavourites', null)
|
||||
}
|
||||
} else {
|
||||
this.$store.dispatch('removeFromFavourites', this.item)
|
||||
}
|
||||
},
|
||||
createFolder() {
|
||||
events.$emit('popup:open', {name: 'create-folder'})
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$store.dispatch('getTeamFolder', this.$route.params.id)
|
||||
// Add to favourites all selected folders
|
||||
if (this.clipboard.includes(this.item)) {
|
||||
this.$store.dispatch('addToFavourites', null)
|
||||
}
|
||||
} else {
|
||||
this.$store.dispatch('removeFromFavourites', this.item)
|
||||
}
|
||||
},
|
||||
createFolder() {
|
||||
events.$emit('popup:open', { name: 'create-folder' })
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.$store.dispatch('getTeamFolder', this.$route.params.id)
|
||||
|
||||
events.$on('context-menu:show', (event, item) => this.item = item)
|
||||
events.$on('mobile-context-menu:show', item => this.item = item)
|
||||
events.$on('context-menu:current-folder', folder => this.item = folder)
|
||||
events.$on('context-menu:show', (event, item) => (this.item = item))
|
||||
events.$on('mobile-context-menu:show', (item) => (this.item = item))
|
||||
events.$on('context-menu:current-folder', (folder) => (this.item = folder))
|
||||
|
||||
events.$on('action:confirmed', data => {
|
||||
events.$on('action:confirmed', (data) => {
|
||||
if (data.operation === 'dissolve-team-folder')
|
||||
axios
|
||||
.delete(`/api/teams/folders/${data.id}`)
|
||||
.then(() => {
|
||||
if (this.$route.params.id) {
|
||||
this.$router.push({ name: 'TeamFolders' })
|
||||
} else {
|
||||
this.$store.commit('REMOVE_ITEM', data.id)
|
||||
}
|
||||
|
||||
if (data.operation === 'dissolve-team-folder')
|
||||
axios.delete(`/api/teams/folders/${data.id}`)
|
||||
.then(() => {
|
||||
if (this.$route.params.id) {
|
||||
this.$router.push({name: 'TeamFolders'})
|
||||
} else {
|
||||
this.$store.commit('REMOVE_ITEM', data.id)
|
||||
}
|
||||
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('Your Team Folder was moved into your files.'),
|
||||
})
|
||||
})
|
||||
.catch(() => this.$isSomethingWrong())
|
||||
})
|
||||
},
|
||||
destroyed() {
|
||||
events.$off('action:confirmed')
|
||||
},
|
||||
}
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('Your Team Folder was moved into your files.'),
|
||||
})
|
||||
})
|
||||
.catch(() => this.$isSomethingWrong())
|
||||
})
|
||||
},
|
||||
destroyed() {
|
||||
events.$off('action:confirmed')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,123 +1,127 @@
|
||||
<template>
|
||||
<div>
|
||||
<ContextMenu>
|
||||
<template v-slot:empty-select>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$emptyTrash" :title="$t('context_menu.empty_trash')" icon="empty-trash" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
<div>
|
||||
<ContextMenu>
|
||||
<template v-slot:empty-select>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$emptyTrash" :title="$t('context_menu.empty_trash')" icon="empty-trash" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
|
||||
<template v-slot:single-select v-if="item">
|
||||
<OptionGroup>
|
||||
<Option @click.native="$restoreFileOrFolder(item)" v-if="item" :title="$t('context_menu.restore')" icon="restore" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" v-if="item" :title="$t('context_menu.delete')" icon="trash" />
|
||||
<Option @click.native="$emptyTrash" :title="$t('context_menu.empty_trash')" icon="empty-trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$openInDetailPanel(item)" :title="$t('context_menu.detail')" icon="detail" />
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
<template v-slot:single-select v-if="item">
|
||||
<OptionGroup>
|
||||
<Option @click.native="$restoreFileOrFolder(item)" v-if="item" :title="$t('context_menu.restore')" icon="restore" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" v-if="item" :title="$t('context_menu.delete')" icon="trash" />
|
||||
<Option @click.native="$emptyTrash" :title="$t('context_menu.empty_trash')" icon="empty-trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$openInDetailPanel(item)" :title="$t('context_menu.detail')" icon="detail" />
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
|
||||
<template v-slot:multiple-select v-if="item">
|
||||
<OptionGroup>
|
||||
<Option @click.native="$restoreFileOrFolder(item)" v-if="item" :title="$t('context_menu.restore')" icon="restore" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
<Option @click.native="$emptyTrash" :title="$t('context_menu.empty_trash')" icon="empty-trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
</ContextMenu>
|
||||
<template v-slot:multiple-select v-if="item">
|
||||
<OptionGroup>
|
||||
<Option @click.native="$restoreFileOrFolder(item)" v-if="item" :title="$t('context_menu.restore')" icon="restore" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
<Option @click.native="$emptyTrash" :title="$t('context_menu.empty_trash')" icon="empty-trash" />
|
||||
</OptionGroup>
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection()" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</template>
|
||||
</ContextMenu>
|
||||
|
||||
<MobileContextMenu>
|
||||
<OptionGroup v-if="item">
|
||||
<Option @click.native="$restoreFileOrFolder(item)" v-if="item" :title="$t('context_menu.restore')" icon="restore" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
<MobileContextMenu>
|
||||
<OptionGroup v-if="item">
|
||||
<Option @click.native="$restoreFileOrFolder(item)" v-if="item" :title="$t('context_menu.restore')" icon="restore" />
|
||||
<Option @click.native="$deleteFileOrFolder(item)" :title="$t('context_menu.delete')" icon="trash" />
|
||||
</OptionGroup>
|
||||
|
||||
<OptionGroup>
|
||||
<Option @click.native="$downloadSelection(item)" :title="$t('context_menu.download')" icon="download" />
|
||||
</OptionGroup>
|
||||
</MobileContextMenu>
|
||||
</MobileContextMenu>
|
||||
|
||||
<FileActionsMobile>
|
||||
<MobileActionButton @click.native="$openSpotlight()" icon="search">
|
||||
{{ $t('Spotlight')}}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-filter')" :icon="$getCurrentSectionIcon()">
|
||||
{{ $getCurrentSectionName() }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$emptyTrash" icon="trash">
|
||||
{{ $t('context_menu.empty_trash') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$enableMultiSelectMode" icon="check-square">
|
||||
{{ $t('context_menu.select') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-sorting')" icon="preview-sorting">
|
||||
{{ $t('preview_sorting.preview_sorting_button') }}
|
||||
</MobileActionButton>
|
||||
</FileActionsMobile>
|
||||
<FileActionsMobile>
|
||||
<MobileActionButton @click.native="$openSpotlight()" icon="search">
|
||||
{{ $t('Spotlight') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-filter')" :icon="$getCurrentSectionIcon()">
|
||||
{{ $getCurrentSectionName() }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$emptyTrash" icon="trash">
|
||||
{{ $t('context_menu.empty_trash') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$enableMultiSelectMode" icon="check-square">
|
||||
{{ $t('context_menu.select') }}
|
||||
</MobileActionButton>
|
||||
<MobileActionButton @click.native="$showMobileMenu('file-sorting')" icon="preview-sorting">
|
||||
{{ $t('preview_sorting.preview_sorting_button') }}
|
||||
</MobileActionButton>
|
||||
</FileActionsMobile>
|
||||
|
||||
<EmptyFilePage>
|
||||
<h1 class="title">{{ $t('Your Trash is Empty') }}</h1>
|
||||
</EmptyFilePage>
|
||||
<EmptyFilePage>
|
||||
<h1 class="title">{{ $t('Your Trash is Empty') }}</h1>
|
||||
</EmptyFilePage>
|
||||
|
||||
<FileBrowser />
|
||||
<FileBrowser />
|
||||
|
||||
<MobileMultiSelectToolbar>
|
||||
<ToolbarButton @click.native="$deleteFileOrFolder(clipboard)" class="action-btn" source="trash" :class="{'is-inactive' : clipboard.length < 1}" :action="$t('actions.delete')" />
|
||||
<ToolbarButton @click.native="$downloadSelection(item)" class="action-btn" source="download" :action="$t('actions.download')" />
|
||||
</MobileMultiSelectToolbar>
|
||||
</div>
|
||||
<MobileMultiSelectToolbar>
|
||||
<ToolbarButton
|
||||
@click.native="$deleteFileOrFolder(clipboard)"
|
||||
class="action-btn"
|
||||
source="trash"
|
||||
:class="{ 'is-inactive': clipboard.length < 1 }"
|
||||
:action="$t('actions.delete')"
|
||||
/>
|
||||
<ToolbarButton @click.native="$downloadSelection(item)" class="action-btn" source="download" :action="$t('actions.download')" />
|
||||
</MobileMultiSelectToolbar>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import EmptyFilePage from "../../components/FilesView/EmptyFilePage";
|
||||
import FileActionsMobile from "../../components/FilesView/FileActionsMobile";
|
||||
import MobileActionButtonUpload from "../../components/FilesView/MobileActionButtonUpload";
|
||||
import MobileActionButton from "../../components/FilesView/MobileActionButton";
|
||||
import MobileMultiSelectToolbar from "../../components/FilesView/MobileMultiSelectToolbar";
|
||||
import MobileContextMenu from "../../components/FilesView/MobileContextMenu";
|
||||
import ToolbarButton from "../../components/FilesView/ToolbarButton";
|
||||
import FileBrowser from "../../components/FilesView/FileBrowser";
|
||||
import ContextMenu from "../../components/FilesView/ContextMenu";
|
||||
import OptionGroup from "../../components/FilesView/OptionGroup";
|
||||
import Option from "../../components/FilesView/Option";
|
||||
import { mapGetters } from 'vuex'
|
||||
import {events} from "../../bus";
|
||||
import EmptyFilePage from '../../components/FilesView/EmptyFilePage'
|
||||
import FileActionsMobile from '../../components/FilesView/FileActionsMobile'
|
||||
import MobileActionButtonUpload from '../../components/FilesView/MobileActionButtonUpload'
|
||||
import MobileActionButton from '../../components/FilesView/MobileActionButton'
|
||||
import MobileMultiSelectToolbar from '../../components/FilesView/MobileMultiSelectToolbar'
|
||||
import MobileContextMenu from '../../components/FilesView/MobileContextMenu'
|
||||
import ToolbarButton from '../../components/FilesView/ToolbarButton'
|
||||
import FileBrowser from '../../components/FilesView/FileBrowser'
|
||||
import ContextMenu from '../../components/FilesView/ContextMenu'
|
||||
import OptionGroup from '../../components/FilesView/OptionGroup'
|
||||
import Option from '../../components/FilesView/Option'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { events } from '../../bus'
|
||||
|
||||
export default {
|
||||
name: 'Trash',
|
||||
components: {
|
||||
MobileActionButtonUpload,
|
||||
MobileMultiSelectToolbar,
|
||||
MobileActionButton,
|
||||
MobileContextMenu,
|
||||
ToolbarButton,
|
||||
OptionGroup,
|
||||
FileBrowser,
|
||||
ContextMenu,
|
||||
Option,
|
||||
FileActionsMobile,
|
||||
EmptyFilePage,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'clipboard',
|
||||
]),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
item: undefined,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$store.dispatch('getTrash', this.$route.params.id)
|
||||
export default {
|
||||
name: 'Trash',
|
||||
components: {
|
||||
MobileActionButtonUpload,
|
||||
MobileMultiSelectToolbar,
|
||||
MobileActionButton,
|
||||
MobileContextMenu,
|
||||
ToolbarButton,
|
||||
OptionGroup,
|
||||
FileBrowser,
|
||||
ContextMenu,
|
||||
Option,
|
||||
FileActionsMobile,
|
||||
EmptyFilePage,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['clipboard']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
item: undefined,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$store.dispatch('getTrash', this.$route.params.id)
|
||||
|
||||
events.$on('context-menu:show', (event, item) => this.item = item)
|
||||
events.$on('mobile-context-menu:show', item => this.item = item)
|
||||
}
|
||||
}
|
||||
events.$on('context-menu:show', (event, item) => (this.item = item))
|
||||
events.$on('mobile-context-menu:show', (item) => (this.item = item))
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,40 +1,37 @@
|
||||
<template>
|
||||
<div class="landing-page">
|
||||
|
||||
<!--Navigation-->
|
||||
<Navigation class="page-wrapper small"/>
|
||||
<Navigation class="page-wrapper small" />
|
||||
|
||||
<!--Page content-->
|
||||
<div class="page-wrapper small">
|
||||
|
||||
<!--Headline-->
|
||||
<PageTitle
|
||||
class="headline"
|
||||
:title="$t('page_contact_us.title')"
|
||||
:description="$t('page_contact_us.description')"
|
||||
></PageTitle>
|
||||
|
||||
<ValidationObserver v-if="! isSuccess" @submit.prevent="contactForm" ref="contactForm" v-slot="{ invalid }" tag="form"
|
||||
class="form block-form">
|
||||
<PageTitle class="headline" :title="$t('page_contact_us.title')" :description="$t('page_contact_us.description')"></PageTitle>
|
||||
|
||||
<ValidationObserver v-if="!isSuccess" @submit.prevent="contactForm" ref="contactForm" v-slot="{ invalid }" tag="form" class="form block-form">
|
||||
<div class="block-wrapper">
|
||||
<label>{{ $t('page_contact_us.form.email') }}:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="E-Mail" rules="required"
|
||||
v-slot="{ errors }">
|
||||
<input v-model="contact.email" :placeholder="$t('page_contact_us.form.email_plac')" type="email"
|
||||
class="focus-border-theme"
|
||||
:class="{'border-red': errors[0]}"/>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="E-Mail" rules="required" v-slot="{ errors }">
|
||||
<input
|
||||
v-model="contact.email"
|
||||
:placeholder="$t('page_contact_us.form.email_plac')"
|
||||
type="email"
|
||||
class="focus-border-theme"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>{{ $t('page_contact_us.form.message') }}:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Message" rules="required"
|
||||
v-slot="{ errors }">
|
||||
<textarea v-model="contact.message" :placeholder="$t('page_contact_us.form.message_plac')" rows="6"
|
||||
class="focus-border-theme"
|
||||
:class="{'border-red': errors[0]}"
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Message" rules="required" v-slot="{ errors }">
|
||||
<textarea
|
||||
v-model="contact.message"
|
||||
:placeholder="$t('page_contact_us.form.message_plac')"
|
||||
rows="6"
|
||||
class="focus-border-theme"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
></textarea>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
@@ -45,7 +42,7 @@
|
||||
</InfoBox>
|
||||
|
||||
<div>
|
||||
<AuthButton class="submit-button" icon="chevron-right" :text="$t('page_contact_us.form.submit_button')" :loading="isLoading" :disabled="isLoading"/>
|
||||
<AuthButton class="submit-button" icon="chevron-right" :text="$t('page_contact_us.form.submit_button')" :loading="isLoading" :disabled="isLoading" />
|
||||
</div>
|
||||
</ValidationObserver>
|
||||
<InfoBox v-if="isSuccess">
|
||||
@@ -54,119 +51,116 @@
|
||||
</div>
|
||||
|
||||
<!--Footer-->
|
||||
<PageFooter/>
|
||||
<PageFooter />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import PageTitle from "../../components/Index/Components/PageTitle";
|
||||
import PageFooter from '../../components/Index/IndexPageFooter'
|
||||
import Navigation from '../../components/Index/IndexNavigation'
|
||||
import InfoBox from "../../components/Others/Forms/InfoBox";
|
||||
import AuthButton from "../../components/Auth/AuthButton";
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {mapGetters} from 'vuex'
|
||||
import axios from 'axios'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import PageTitle from '../../components/Index/Components/PageTitle'
|
||||
import PageFooter from '../../components/Index/IndexPageFooter'
|
||||
import Navigation from '../../components/Index/IndexNavigation'
|
||||
import InfoBox from '../../components/Others/Forms/InfoBox'
|
||||
import AuthButton from '../../components/Auth/AuthButton'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'ContactUs',
|
||||
components: {
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AuthButton,
|
||||
PageFooter,
|
||||
Navigation,
|
||||
PageTitle,
|
||||
required,
|
||||
InfoBox,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
isSuccess: false,
|
||||
isError: false,
|
||||
contact: {
|
||||
email: '',
|
||||
message: '',
|
||||
reCaptcha: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async contactForm() {
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.contactForm.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Get ReCaptcha token
|
||||
if(config.allowedRecaptcha) {
|
||||
this.register.reCaptcha = await this.$reCaptchaToken('register').then((response) => {
|
||||
return response
|
||||
})
|
||||
}
|
||||
|
||||
// Send request to get user token
|
||||
axios
|
||||
.post('/api/contact', this.contact)
|
||||
.then(() => {
|
||||
this.isSuccess = true
|
||||
})
|
||||
.catch(() => {
|
||||
this.isError = true
|
||||
})
|
||||
.finally(() => {
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
export default {
|
||||
name: 'ContactUs',
|
||||
components: {
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AuthButton,
|
||||
PageFooter,
|
||||
Navigation,
|
||||
PageTitle,
|
||||
required,
|
||||
InfoBox,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
isSuccess: false,
|
||||
isError: false,
|
||||
contact: {
|
||||
email: '',
|
||||
message: '',
|
||||
reCaptcha: null,
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async contactForm() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.contactForm.validate()
|
||||
|
||||
if (!isValid) return
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Get ReCaptcha token
|
||||
if (config.allowedRecaptcha) {
|
||||
this.register.reCaptcha = await this.$reCaptchaToken('register').then((response) => {
|
||||
return response
|
||||
})
|
||||
}
|
||||
|
||||
// Send request to get user token
|
||||
axios
|
||||
.post('/api/contact', this.contact)
|
||||
.then(() => {
|
||||
this.isSuccess = true
|
||||
})
|
||||
.catch(() => {
|
||||
this.isError = true
|
||||
})
|
||||
.finally(() => {
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../../sass/vuefilemanager/landing-page';
|
||||
@import '../../../sass/vuefilemanager/variables';
|
||||
@import '../../../sass/vuefilemanager/mixins';
|
||||
@import '../../../sass/vuefilemanager/forms';
|
||||
@import '../../../sass/vuefilemanager/landing-page';
|
||||
@import '../../../sass/vuefilemanager/variables';
|
||||
@import '../../../sass/vuefilemanager/mixins';
|
||||
@import '../../../sass/vuefilemanager/forms';
|
||||
|
||||
.form {
|
||||
max-width: 100%;
|
||||
.form {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.headline {
|
||||
padding-top: 70px;
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
|
||||
.form.block-form {
|
||||
.submit-button {
|
||||
margin-top: 20px;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.dark {
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 960px) {
|
||||
.headline {
|
||||
padding-top: 70px;
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
|
||||
.form.block-form {
|
||||
|
||||
.submit-button {
|
||||
margin-top: 20px;
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.dark {
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 960px) {
|
||||
.headline {
|
||||
padding-top: 50px;
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
padding-top: 50px;
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,99 +1,91 @@
|
||||
<template>
|
||||
<div class="landing-page">
|
||||
|
||||
<!--Navigation-->
|
||||
<Navigation class="page-wrapper small"/>
|
||||
<Navigation class="page-wrapper small" />
|
||||
|
||||
<!--Page content-->
|
||||
<div class="page-wrapper small">
|
||||
|
||||
<!--Headline-->
|
||||
<PageTitle
|
||||
class="headline"
|
||||
:title="page.data.attributes.title"
|
||||
></PageTitle>
|
||||
<PageTitle class="headline" :title="page.data.attributes.title"></PageTitle>
|
||||
|
||||
<!--Content-->
|
||||
<div class="page-content" v-html="page.data.attributes.content_formatted"></div>
|
||||
</div>
|
||||
|
||||
<!--Footer-->
|
||||
<PageFooter/>
|
||||
<PageFooter />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PageTitle from "../../components/Index/Components/PageTitle";
|
||||
import PageFooter from '../../components/Index/IndexPageFooter'
|
||||
import Navigation from '../../components/Index/IndexNavigation'
|
||||
import {mapGetters} from 'vuex'
|
||||
import axios from 'axios'
|
||||
import PageTitle from '../../components/Index/Components/PageTitle'
|
||||
import PageFooter from '../../components/Index/IndexPageFooter'
|
||||
import Navigation from '../../components/Index/IndexNavigation'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'DynamicPage',
|
||||
components: {
|
||||
PageFooter,
|
||||
Navigation,
|
||||
PageTitle,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
page: undefined,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route(to, from) {
|
||||
this.getPage()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getPage() {
|
||||
axios.get('/api/page/' + this.$route.params.slug)
|
||||
.then(response => {
|
||||
this.page = response.data
|
||||
|
||||
this.$scrollTop()
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getPage()
|
||||
export default {
|
||||
name: 'DynamicPage',
|
||||
components: {
|
||||
PageFooter,
|
||||
Navigation,
|
||||
PageTitle,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
page: undefined,
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route(to, from) {
|
||||
this.getPage()
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getPage() {
|
||||
axios.get('/api/page/' + this.$route.params.slug).then((response) => {
|
||||
this.page = response.data
|
||||
|
||||
this.$scrollTop()
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getPage()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../../sass/vuefilemanager/landing-page';
|
||||
@import '../../../sass/vuefilemanager/variables';
|
||||
@import '../../../sass/vuefilemanager/mixins';
|
||||
@import '../../../sass/vuefilemanager/landing-page';
|
||||
@import '../../../sass/vuefilemanager/variables';
|
||||
@import '../../../sass/vuefilemanager/mixins';
|
||||
|
||||
.headline {
|
||||
padding-top: 70px;
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
|
||||
.page-content {
|
||||
/deep/ p {
|
||||
@include font-size(20);
|
||||
font-weight: 500;
|
||||
line-height: 1.65;
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.dark {
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 960px) {
|
||||
.headline {
|
||||
padding-top: 70px;
|
||||
padding-bottom: 50px;
|
||||
}
|
||||
|
||||
.page-content {
|
||||
|
||||
/deep/ p {
|
||||
@include font-size(20);
|
||||
font-weight: 500;
|
||||
line-height: 1.65;
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
}
|
||||
|
||||
.dark {
|
||||
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 960px) {
|
||||
.headline {
|
||||
padding-top: 50px;
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
padding-top: 50px;
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="landing-page">
|
||||
<div v-if="! isLoading">
|
||||
<div v-if="!isLoading">
|
||||
<!--Navigation-->
|
||||
<Navigation class="page-wrapper medium" />
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<MainFeatures />
|
||||
|
||||
<!--Pricing Tables-->
|
||||
<!-- <PricingTables v-if="config.isSaaS" />-->
|
||||
<!-- <PricingTables v-if="config.isSaaS" />-->
|
||||
|
||||
<!--Get Started Call To Action-->
|
||||
<GetStarted />
|
||||
@@ -29,63 +29,62 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import HeroScreenshot from '../../components/Index/IndexHeroScreenshot'
|
||||
import PricingTables from '../../components/Index/IndexPricingTables'
|
||||
import MainFeatures from '../../components/Index/IndexMainFeatures'
|
||||
import Navigation from '../../components/Index/IndexNavigation'
|
||||
import PageHeader from '../../components/Index/IndexPageHeader'
|
||||
import GetStarted from '../../components/Index/IndexGetStarted'
|
||||
import PageFooter from '../../components/Index/IndexPageFooter'
|
||||
import Spinner from "../../components/FilesView/Spinner";
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
import HeroScreenshot from '../../components/Index/IndexHeroScreenshot'
|
||||
import PricingTables from '../../components/Index/IndexPricingTables'
|
||||
import MainFeatures from '../../components/Index/IndexMainFeatures'
|
||||
import Navigation from '../../components/Index/IndexNavigation'
|
||||
import PageHeader from '../../components/Index/IndexPageHeader'
|
||||
import GetStarted from '../../components/Index/IndexGetStarted'
|
||||
import PageFooter from '../../components/Index/IndexPageFooter'
|
||||
import Spinner from '../../components/FilesView/Spinner'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'Homepage',
|
||||
components: {
|
||||
HeroScreenshot,
|
||||
PricingTables,
|
||||
MainFeatures,
|
||||
GetStarted,
|
||||
Navigation,
|
||||
PageHeader,
|
||||
PageFooter,
|
||||
Spinner,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
if (! this.config.allowHomepage)
|
||||
this.$router.push({name: 'SignIn'})
|
||||
|
||||
// Get page content
|
||||
axios.get('/api/settings', {
|
||||
params: {
|
||||
column: 'allow_homepage|footer_content|get_started_description|get_started_title|pricing_description|pricing_title|feature_description_3|feature_title_3|feature_description_2|feature_title_2|feature_description_1|feature_title_1|features_description|features_title|header_description|header_title|section_get_started|section_pricing_content|section_feature_boxes|section_features'
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
this.$store.commit('SET_INDEX_CONTENT', response.data)
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
export default {
|
||||
name: 'Homepage',
|
||||
components: {
|
||||
HeroScreenshot,
|
||||
PricingTables,
|
||||
MainFeatures,
|
||||
GetStarted,
|
||||
Navigation,
|
||||
PageHeader,
|
||||
PageFooter,
|
||||
Spinner,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (!this.config.allowHomepage) this.$router.push({ name: 'SignIn' })
|
||||
|
||||
// Get page content
|
||||
axios
|
||||
.get('/api/settings', {
|
||||
params: {
|
||||
column: 'allow_homepage|footer_content|get_started_description|get_started_title|pricing_description|pricing_title|feature_description_3|feature_title_3|feature_description_2|feature_title_2|feature_description_1|feature_title_1|features_description|features_title|header_description|header_title|section_get_started|section_pricing_content|section_feature_boxes|section_features',
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
this.$store.commit('SET_INDEX_CONTENT', response.data)
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '../../../sass/vuefilemanager/landing-page';
|
||||
@import '../../../sass/vuefilemanager/variables';
|
||||
@import '../../../sass/vuefilemanager/mixins';
|
||||
@import '../../../sass/vuefilemanager/landing-page';
|
||||
@import '../../../sass/vuefilemanager/variables';
|
||||
@import '../../../sass/vuefilemanager/mixins';
|
||||
</style>
|
||||
|
||||
@@ -1,36 +1,38 @@
|
||||
<template>
|
||||
<div class="flex text-center py-5 px-5 w-full justify-between items-center z-20 lg:hidden block">
|
||||
<div class="z-20 block flex w-full items-center justify-between py-5 px-5 text-center lg:hidden">
|
||||
<!--Location Title-->
|
||||
<div
|
||||
class="inline-block overflow-hidden text-ellipsis whitespace-nowrap align-middle text-sm font-bold transition-all duration-200 dark:text-gray-100"
|
||||
style="max-width: 200px"
|
||||
>
|
||||
{{ locationName }}
|
||||
</div>
|
||||
|
||||
<!--Location Title-->
|
||||
<div class="text-sm dark:text-gray-100 align-middle font-bold overflow-hidden text-ellipsis inline-block whitespace-nowrap transition-all duration-200" style="max-width: 200px;">
|
||||
{{ locationName }}
|
||||
</div>
|
||||
|
||||
<!--More Actions-->
|
||||
<div class="flex items-center">
|
||||
<div @click="$openSpotlight()" class="px-2 mr-4 cursor-pointer">
|
||||
<search-icon size="17" class="vue-feather dark:text-gray-100" />
|
||||
</div>
|
||||
<div @click="$showMobileMenu('user-navigation')" class="pr-1.5 cursor-pointer">
|
||||
<menu-icon size="17" class="vue-feather dark:text-gray-100" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--More Actions-->
|
||||
<div class="flex items-center">
|
||||
<div @click="$openSpotlight()" class="mr-4 cursor-pointer px-2">
|
||||
<search-icon size="17" class="vue-feather dark:text-gray-100" />
|
||||
</div>
|
||||
<div @click="$showMobileMenu('user-navigation')" class="cursor-pointer pr-1.5">
|
||||
<menu-icon size="17" class="vue-feather dark:text-gray-100" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import {MenuIcon, ChevronLeftIcon, SearchIcon } from 'vue-feather-icons'
|
||||
import { MenuIcon, ChevronLeftIcon, SearchIcon } from 'vue-feather-icons'
|
||||
|
||||
export default {
|
||||
name: 'MobileNavigationToolbar',
|
||||
components: {
|
||||
ChevronLeftIcon,
|
||||
SearchIcon,
|
||||
MenuIcon,
|
||||
},
|
||||
computed: {
|
||||
locationName() {
|
||||
return this.$t(this.$route.meta.title)
|
||||
}
|
||||
}
|
||||
}
|
||||
export default {
|
||||
name: 'MobileNavigationToolbar',
|
||||
components: {
|
||||
ChevronLeftIcon,
|
||||
SearchIcon,
|
||||
MenuIcon,
|
||||
},
|
||||
computed: {
|
||||
locationName() {
|
||||
return this.$t(this.$route.meta.title)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
<template>
|
||||
<AuthContentWrapper ref="auth">
|
||||
<AuthContent :visible="true">
|
||||
<Headline
|
||||
:title="$t('page_shared_404.title')"
|
||||
:description="$t('page_shared_404.subtitle')"
|
||||
/>
|
||||
<span class="additional-link">{{ $t('page_registration.have_an_account') }}
|
||||
<router-link :to="{name: 'SignIn'}">
|
||||
<Headline :title="$t('page_shared_404.title')" :description="$t('page_shared_404.subtitle')" />
|
||||
<span class="additional-link"
|
||||
>{{ $t('page_registration.have_an_account') }}
|
||||
<router-link :to="{ name: 'SignIn' }">
|
||||
{{ $t('page_forgotten_password.password_remember_button') }}
|
||||
</router-link>
|
||||
</span>
|
||||
@@ -15,22 +13,22 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AuthContentWrapper from "../components/Auth/AuthContentWrapper";
|
||||
import AuthContent from "../components/Auth/AuthContent";
|
||||
import AuthButton from "../components/Auth/AuthButton";
|
||||
import Headline from "./Auth/Headline"
|
||||
import AuthContentWrapper from '../components/Auth/AuthContentWrapper'
|
||||
import AuthContent from '../components/Auth/AuthContent'
|
||||
import AuthButton from '../components/Auth/AuthButton'
|
||||
import Headline from './Auth/Headline'
|
||||
|
||||
export default {
|
||||
name: 'NotFound',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
Headline,
|
||||
},
|
||||
}
|
||||
export default {
|
||||
name: 'NotFound',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
Headline,
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../../sass/vuefilemanager/auth';
|
||||
@import '../../sass/vuefilemanager/auth';
|
||||
</style>
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
<template>
|
||||
<div class="lg:flex lg:h-screen lg:overflow-hidden">
|
||||
|
||||
<!--On Top of App Components-->
|
||||
<FilePreview />
|
||||
<Spotlight />
|
||||
<Spotlight />
|
||||
|
||||
<!--Popups-->
|
||||
<!--Popups-->
|
||||
<ProcessingPopup />
|
||||
<ConfirmPopup />
|
||||
|
||||
<CreateTeamFolderPopup />
|
||||
<EditTeamFolderPopup />
|
||||
<CreateTeamFolderPopup />
|
||||
<EditTeamFolderPopup />
|
||||
|
||||
<ShareCreatePopup />
|
||||
<ShareEditPopup />
|
||||
@@ -19,111 +18,100 @@
|
||||
<RenameItemPopup />
|
||||
<MoveItemPopup />
|
||||
|
||||
<!--Mobile components-->
|
||||
<!--Mobile components-->
|
||||
<FileSortingMobile />
|
||||
<FileFilterMobile />
|
||||
|
||||
<!--Navigations-->
|
||||
<!--Navigations-->
|
||||
<MobileNavigation />
|
||||
|
||||
<!--Others-->
|
||||
<!--Others-->
|
||||
<DragUI />
|
||||
|
||||
<!--2 col Sidebars-->
|
||||
<!--2 col Sidebars-->
|
||||
<SidebarNavigation />
|
||||
<PanelNavigationFiles />
|
||||
<PanelNavigationFiles />
|
||||
|
||||
<div
|
||||
@contextmenu.prevent.capture="contextMenu($event, undefined)"
|
||||
class="lg:grid lg:content-start lg:flex-grow lg:px-3.5 transition-transform duration-200"
|
||||
>
|
||||
<DesktopToolbar />
|
||||
<div @contextmenu.prevent.capture="contextMenu($event, undefined)" class="transition-transform duration-200 lg:grid lg:flex-grow lg:content-start lg:px-3.5">
|
||||
<DesktopToolbar />
|
||||
|
||||
<MobileToolbar />
|
||||
<MobileToolbar />
|
||||
|
||||
<!--File list & info sidebar-->
|
||||
<div class="flex space-x-3 lg:overflow-hidden lg:h-screen">
|
||||
<!--File list & info sidebar-->
|
||||
<div class="flex space-x-3 lg:h-screen lg:overflow-hidden">
|
||||
<router-view id="file-view" class="relative w-full" :key="$route.fullPath" />
|
||||
|
||||
<router-view
|
||||
id="file-view"
|
||||
class="relative w-full"
|
||||
:key="$route.fullPath"
|
||||
/>
|
||||
|
||||
<InfoSidebar v-if="isVisibleSidebar" />
|
||||
</div>
|
||||
</div>
|
||||
<InfoSidebar v-if="isVisibleSidebar" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import FileSortingMobile from "../components/FilesView/FileSortingMobile";
|
||||
import SidebarNavigation from "../components/Sidebar/SidebarNavigation";
|
||||
import FileFilterMobile from '../components/FilesView/FileFilterMobile'
|
||||
import CreateFolderPopup from '../components/Others/CreateFolderPopup'
|
||||
import ProcessingPopup from '../components/FilesView/ProcessingPopup'
|
||||
import MobileNavigation from '../components/Others/MobileNavigation'
|
||||
import ShareCreatePopup from '../components/Others/ShareCreatePopup'
|
||||
import DesktopToolbar from '../components/FilesView/DesktopToolbar'
|
||||
import CreateTeamFolderPopup from "../components/Teams/CreateTeamFolderPopup"
|
||||
import ConfirmPopup from '../components/Others/Popup/ConfirmPopup'
|
||||
import RenameItemPopup from '../components/Others/RenameItemPopup'
|
||||
import PanelNavigationFiles from "./FileView/Components/PanelNavigationFiles"
|
||||
import MobileToolbar from '../components/FilesView/MobileToolbar'
|
||||
import ShareEditPopup from '../components/Others/ShareEditPopup'
|
||||
import FilePreview from '../components/FilePreview/FilePreview'
|
||||
import MoveItemPopup from '../components/Others/MoveItemPopup'
|
||||
import EditTeamFolderPopup from "../components/Teams/EditTeamFolderPopup"
|
||||
import Spotlight from '../components/Spotlight/Spotlight'
|
||||
import DragUI from '../components/FilesView/DragUI'
|
||||
import InfoSidebar from "../components/FilesView/InfoSidebar"
|
||||
import {events} from '../bus'
|
||||
import {mapGetters} from "vuex"
|
||||
import FileSortingMobile from '../components/FilesView/FileSortingMobile'
|
||||
import SidebarNavigation from '../components/Sidebar/SidebarNavigation'
|
||||
import FileFilterMobile from '../components/FilesView/FileFilterMobile'
|
||||
import CreateFolderPopup from '../components/Others/CreateFolderPopup'
|
||||
import ProcessingPopup from '../components/FilesView/ProcessingPopup'
|
||||
import MobileNavigation from '../components/Others/MobileNavigation'
|
||||
import ShareCreatePopup from '../components/Others/ShareCreatePopup'
|
||||
import DesktopToolbar from '../components/FilesView/DesktopToolbar'
|
||||
import CreateTeamFolderPopup from '../components/Teams/CreateTeamFolderPopup'
|
||||
import ConfirmPopup from '../components/Others/Popup/ConfirmPopup'
|
||||
import RenameItemPopup from '../components/Others/RenameItemPopup'
|
||||
import PanelNavigationFiles from './FileView/Components/PanelNavigationFiles'
|
||||
import MobileToolbar from '../components/FilesView/MobileToolbar'
|
||||
import ShareEditPopup from '../components/Others/ShareEditPopup'
|
||||
import FilePreview from '../components/FilePreview/FilePreview'
|
||||
import MoveItemPopup from '../components/Others/MoveItemPopup'
|
||||
import EditTeamFolderPopup from '../components/Teams/EditTeamFolderPopup'
|
||||
import Spotlight from '../components/Spotlight/Spotlight'
|
||||
import DragUI from '../components/FilesView/DragUI'
|
||||
import InfoSidebar from '../components/FilesView/InfoSidebar'
|
||||
import { events } from '../bus'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Platform',
|
||||
components: {
|
||||
CreateTeamFolderPopup,
|
||||
PanelNavigationFiles,
|
||||
EditTeamFolderPopup,
|
||||
CreateFolderPopup,
|
||||
FileSortingMobile,
|
||||
SidebarNavigation,
|
||||
FileFilterMobile,
|
||||
MobileNavigation,
|
||||
ShareCreatePopup,
|
||||
ProcessingPopup,
|
||||
RenameItemPopup,
|
||||
ShareEditPopup,
|
||||
DesktopToolbar,
|
||||
MoveItemPopup,
|
||||
MobileToolbar,
|
||||
ConfirmPopup,
|
||||
InfoSidebar,
|
||||
FilePreview,
|
||||
Spotlight,
|
||||
DragUI,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'isVisibleSidebar',
|
||||
'isLimitedUser',
|
||||
])
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isScaledDown: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
contextMenu(event, item) {
|
||||
events.$emit('context-menu:show', event, item)
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// TODO: new scaledown effect
|
||||
events.$on('mobile-menu:show', () => this.isScaledDown = true)
|
||||
events.$on('mobile-menu:hide', () => this.isScaledDown = false)
|
||||
}
|
||||
}
|
||||
export default {
|
||||
name: 'Platform',
|
||||
components: {
|
||||
CreateTeamFolderPopup,
|
||||
PanelNavigationFiles,
|
||||
EditTeamFolderPopup,
|
||||
CreateFolderPopup,
|
||||
FileSortingMobile,
|
||||
SidebarNavigation,
|
||||
FileFilterMobile,
|
||||
MobileNavigation,
|
||||
ShareCreatePopup,
|
||||
ProcessingPopup,
|
||||
RenameItemPopup,
|
||||
ShareEditPopup,
|
||||
DesktopToolbar,
|
||||
MoveItemPopup,
|
||||
MobileToolbar,
|
||||
ConfirmPopup,
|
||||
InfoSidebar,
|
||||
FilePreview,
|
||||
Spotlight,
|
||||
DragUI,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['isVisibleSidebar', 'isLimitedUser']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isScaledDown: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
contextMenu(event, item) {
|
||||
events.$emit('context-menu:show', event, item)
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
// TODO: new scaledown effect
|
||||
events.$on('mobile-menu:show', () => (this.isScaledDown = true))
|
||||
events.$on('mobile-menu:hide', () => (this.isScaledDown = false))
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,62 +1,60 @@
|
||||
<template>
|
||||
<div class="lg:flex md:h-screen md:overflow-hidden dark:bg-dark-background bg-light-background">
|
||||
<!--On Top of App Components-->
|
||||
<div class="bg-light-background dark:bg-dark-background md:h-screen md:overflow-hidden lg:flex">
|
||||
<!--On Top of App Components-->
|
||||
<FilePreview />
|
||||
<Spotlight />
|
||||
<Spotlight />
|
||||
|
||||
<ConfirmPopup />
|
||||
<ConfirmPopup />
|
||||
|
||||
<ConfirmPassword />
|
||||
<ConfirmPassword />
|
||||
|
||||
<!--2FA popups-->
|
||||
<TwoFactorRecoveryCodesPopup />
|
||||
<TwoFactorQrSetupPopup />
|
||||
<!--2FA popups-->
|
||||
<TwoFactorRecoveryCodesPopup />
|
||||
<TwoFactorQrSetupPopup />
|
||||
|
||||
<!--Access Token Popup-->
|
||||
<CreatePersonalTokenPopup />
|
||||
<!--Access Token Popup-->
|
||||
<CreatePersonalTokenPopup />
|
||||
|
||||
<!--Payments Popup-->
|
||||
<SelectPlanSubscriptionPopup />
|
||||
<SelectSingleChargeMethodPopup />
|
||||
<!--Payments Popup-->
|
||||
<SelectPlanSubscriptionPopup />
|
||||
<SelectSingleChargeMethodPopup />
|
||||
|
||||
<SidebarNavigation />
|
||||
<SidebarNavigation />
|
||||
|
||||
<!--Navigations-->
|
||||
<!--Navigations-->
|
||||
<MobileNavigation />
|
||||
|
||||
<MobileNavigationToolbar />
|
||||
<MobileNavigationToolbar />
|
||||
|
||||
<div v-if="user" class="lg:pt-6 md:px-6 px-2.5 lg:pb-0 pb-12 w-full overflow-x-hidden relative xl:max-w-screen-lg md:max-w-4xl mx-auto">
|
||||
<div v-if="! isLoading" id="page-content">
|
||||
<div v-if="user" class="relative mx-auto w-full overflow-x-hidden px-2.5 pb-12 md:max-w-4xl md:px-6 lg:pt-6 lg:pb-0 xl:max-w-screen-lg">
|
||||
<div v-if="!isLoading" id="page-content">
|
||||
<div class="card sticky top-0 z-10 shadow-card" style="padding-bottom: 0">
|
||||
<!--User thumbnail-->
|
||||
<div class="mb-3 flex items-center">
|
||||
<!--Image input for replace avatar-->
|
||||
<AvatarInput v-model="avatar" :avatar="user.data.relationships.settings.data.attributes.avatar.md" />
|
||||
|
||||
<div class="card shadow-card sticky top-0 z-10" style="padding-bottom: 0">
|
||||
<!--User name & email-->
|
||||
<div class="ml-4">
|
||||
<b class="text-md block font-bold sm:text-lg">
|
||||
{{ user.data.relationships.settings.data.attributes.first_name }}
|
||||
{{ user.data.relationships.settings.data.attributes.last_name }}
|
||||
|
||||
<!--User thumbnail-->
|
||||
<div class="flex items-center mb-3">
|
||||
<ColorLabel v-if="config.subscriptionType === 'fixed'" :color="subscriptionColor">
|
||||
{{ subscriptionStatus }}
|
||||
</ColorLabel>
|
||||
</b>
|
||||
<small class="block text-xs text-gray-600 sm:text-sm">
|
||||
{{ user.data.attributes.email }}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--Image input for replace avatar-->
|
||||
<AvatarInput v-model="avatar" :avatar="user.data.relationships.settings.data.attributes.avatar.md" />
|
||||
<CardNavigation :pages="pages" class="-mx-1" />
|
||||
</div>
|
||||
|
||||
<!--User name & email-->
|
||||
<div class="ml-4">
|
||||
<b class="sm:text-lg text-md font-bold block">
|
||||
{{ user.data.relationships.settings.data.attributes.first_name }} {{ user.data.relationships.settings.data.attributes.last_name }}
|
||||
|
||||
<ColorLabel v-if="config.subscriptionType === 'fixed'" :color="subscriptionColor">
|
||||
{{ subscriptionStatus }}
|
||||
</ColorLabel>
|
||||
</b>
|
||||
<small class="sm:text-sm text-xs text-gray-600 block">
|
||||
{{ user.data.attributes.email }}
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<CardNavigation :pages="pages" class="-mx-1" />
|
||||
</div>
|
||||
|
||||
<!--Router Content-->
|
||||
<router-view :user="user" />
|
||||
<!--Router Content-->
|
||||
<router-view :user="user" />
|
||||
</div>
|
||||
<div id="loader" v-if="isLoading">
|
||||
<Spinner />
|
||||
@@ -66,98 +64,90 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MobileNavigation from "../components/Others/MobileNavigation";
|
||||
import SelectSingleChargeMethodPopup from "../components/Others/SelectSingleChargeMethodPopup";
|
||||
import SelectPlanSubscriptionPopup from "../components/Subscription/SelectPlanSubscriptionPopup";
|
||||
import ConfirmPopup from "../components/Others/Popup/ConfirmPopup";
|
||||
import FilePreview from "../components/FilePreview/FilePreview";
|
||||
import Spotlight from "../components/Spotlight/Spotlight";
|
||||
import TwoFactorRecoveryCodesPopup from "../components/Others/TwoFactorRecoveryCodesPopup";
|
||||
import CreatePersonalTokenPopup from "../components/Others/CreatePersonalTokenPopup";
|
||||
import TwoFactorQrSetupPopup from "../components/Others/TwoFactorQrSetupPopup";
|
||||
import AvatarInput from "../components/Others/Forms/AvatarInput";
|
||||
import SidebarNavigation from "../components/Sidebar/SidebarNavigation"
|
||||
import ColorLabel from "../components/Others/ColorLabel";
|
||||
import Spinner from "../components/FilesView/Spinner";
|
||||
import {mapGetters} from 'vuex'
|
||||
import CardNavigation from "../components/Admin/CardNavigation";
|
||||
import ConfirmPassword from "../components/Others/ConfirmPassword";
|
||||
import MobileNavigationToolbar from "./MobileNavigationToolbar";
|
||||
|
||||
export default {
|
||||
name: 'Settings',
|
||||
components: {
|
||||
MobileNavigationToolbar,
|
||||
MobileNavigation,
|
||||
ConfirmPassword,
|
||||
SelectSingleChargeMethodPopup,
|
||||
SelectPlanSubscriptionPopup,
|
||||
ConfirmPopup,
|
||||
CardNavigation,
|
||||
FilePreview,
|
||||
Spotlight,
|
||||
TwoFactorRecoveryCodesPopup,
|
||||
CreatePersonalTokenPopup,
|
||||
TwoFactorQrSetupPopup,
|
||||
SidebarNavigation,
|
||||
AvatarInput,
|
||||
ColorLabel,
|
||||
Spinner,
|
||||
import MobileNavigation from '../components/Others/MobileNavigation'
|
||||
import SelectSingleChargeMethodPopup from '../components/Others/SelectSingleChargeMethodPopup'
|
||||
import SelectPlanSubscriptionPopup from '../components/Subscription/SelectPlanSubscriptionPopup'
|
||||
import ConfirmPopup from '../components/Others/Popup/ConfirmPopup'
|
||||
import FilePreview from '../components/FilePreview/FilePreview'
|
||||
import Spotlight from '../components/Spotlight/Spotlight'
|
||||
import TwoFactorRecoveryCodesPopup from '../components/Others/TwoFactorRecoveryCodesPopup'
|
||||
import CreatePersonalTokenPopup from '../components/Others/CreatePersonalTokenPopup'
|
||||
import TwoFactorQrSetupPopup from '../components/Others/TwoFactorQrSetupPopup'
|
||||
import AvatarInput from '../components/Others/Forms/AvatarInput'
|
||||
import SidebarNavigation from '../components/Sidebar/SidebarNavigation'
|
||||
import ColorLabel from '../components/Others/ColorLabel'
|
||||
import Spinner from '../components/FilesView/Spinner'
|
||||
import { mapGetters } from 'vuex'
|
||||
import CardNavigation from '../components/Admin/CardNavigation'
|
||||
import ConfirmPassword from '../components/Others/ConfirmPassword'
|
||||
import MobileNavigationToolbar from './MobileNavigationToolbar'
|
||||
|
||||
export default {
|
||||
name: 'Settings',
|
||||
components: {
|
||||
MobileNavigationToolbar,
|
||||
MobileNavigation,
|
||||
ConfirmPassword,
|
||||
SelectSingleChargeMethodPopup,
|
||||
SelectPlanSubscriptionPopup,
|
||||
ConfirmPopup,
|
||||
CardNavigation,
|
||||
FilePreview,
|
||||
Spotlight,
|
||||
TwoFactorRecoveryCodesPopup,
|
||||
CreatePersonalTokenPopup,
|
||||
TwoFactorQrSetupPopup,
|
||||
SidebarNavigation,
|
||||
AvatarInput,
|
||||
ColorLabel,
|
||||
Spinner,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config', 'user']),
|
||||
subscriptionStatus() {
|
||||
return this.user.data.relationships.subscription ? this.$t('global.premium') : this.$t('global.free')
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config',
|
||||
'user',
|
||||
]),
|
||||
subscriptionStatus() {
|
||||
return this.user.data.relationships.subscription
|
||||
? this.$t('global.premium')
|
||||
: this.$t('global.free')
|
||||
},
|
||||
subscriptionColor() {
|
||||
return this.user.data.relationships.subscription
|
||||
? 'green'
|
||||
: 'purple'
|
||||
},
|
||||
canShowUpgradeWarning() {
|
||||
return this.config.storageLimit && this.user.data.attributes.storage.used > 95
|
||||
},
|
||||
canShowIncompletePayment() {
|
||||
return this.user.data.attributes.incomplete_payment
|
||||
},
|
||||
pages() {
|
||||
let list = [
|
||||
{
|
||||
title: this.$t('menu.profile'),
|
||||
route: 'Profile',
|
||||
},
|
||||
{
|
||||
title: this.$t('menu.password'),
|
||||
route: 'Password',
|
||||
},
|
||||
{
|
||||
title: this.$t('menu.storage'),
|
||||
route: 'Storage',
|
||||
},
|
||||
]
|
||||
|
||||
// Push billing item if subscription is set
|
||||
if (['fixed', 'metered'].includes(this.config.subscriptionType)) {
|
||||
list.push({
|
||||
title: this.$t('Billing'),
|
||||
route: 'Billing',
|
||||
})
|
||||
}
|
||||
|
||||
return list
|
||||
}
|
||||
subscriptionColor() {
|
||||
return this.user.data.relationships.subscription ? 'green' : 'purple'
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
avatar: undefined,
|
||||
isLoading: false,
|
||||
canShowUpgradeWarning() {
|
||||
return this.config.storageLimit && this.user.data.attributes.storage.used > 95
|
||||
},
|
||||
canShowIncompletePayment() {
|
||||
return this.user.data.attributes.incomplete_payment
|
||||
},
|
||||
pages() {
|
||||
let list = [
|
||||
{
|
||||
title: this.$t('menu.profile'),
|
||||
route: 'Profile',
|
||||
},
|
||||
{
|
||||
title: this.$t('menu.password'),
|
||||
route: 'Password',
|
||||
},
|
||||
{
|
||||
title: this.$t('menu.storage'),
|
||||
route: 'Storage',
|
||||
},
|
||||
]
|
||||
|
||||
// Push billing item if subscription is set
|
||||
if (['fixed', 'metered'].includes(this.config.subscriptionType)) {
|
||||
list.push({
|
||||
title: this.$t('Billing'),
|
||||
route: 'Billing',
|
||||
})
|
||||
}
|
||||
|
||||
return list
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
avatar: undefined,
|
||||
isLoading: false,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -3,18 +3,17 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapGetters } from 'vuex'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'SetupWizard',
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
mounted() {
|
||||
let status = this.$root.$data.config.installation
|
||||
export default {
|
||||
name: 'SetupWizard',
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
mounted() {
|
||||
let status = this.$root.$data.config.installation
|
||||
|
||||
if (status && status === 'setup-done')
|
||||
this.$router.push({name: 'SignIn'})
|
||||
}
|
||||
}
|
||||
if (status && status === 'setup-done') this.$router.push({ name: 'SignIn' })
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
<template>
|
||||
<AuthContentWrapper ref="auth">
|
||||
|
||||
<!--Database Credentials-->
|
||||
<AuthContent name="database-credentials" :visible="true">
|
||||
<div class="content-headline">
|
||||
<settings-icon size="40" class="title-icon text-theme"/>
|
||||
<settings-icon size="40" class="title-icon text-theme" />
|
||||
<h1>Setup Wizard</h1>
|
||||
<h2>Create your admin account.</h2>
|
||||
</div>
|
||||
@@ -22,7 +21,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Full Name:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Full Name" rules="required" v-slot="{ errors }">
|
||||
<input v-model="admin.name" placeholder="Type your full name" type="text" :class="{'border-red': errors[0]}" />
|
||||
<input v-model="admin.name" placeholder="Type your full name" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -30,7 +29,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Email:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Email" rules="required" v-slot="{ errors }">
|
||||
<input v-model="admin.email" placeholder="Type your email" type="email" :class="{'border-red': errors[0]}" />
|
||||
<input v-model="admin.email" placeholder="Type your email" type="email" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -38,7 +37,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Password:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Password" rules="required|confirmed:confirmation" v-slot="{ errors }">
|
||||
<input v-model="admin.password" placeholder="Type your password" type="password" :class="{'border-red': errors[0]}" />
|
||||
<input v-model="admin.password" placeholder="Type your password" type="password" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -46,166 +45,156 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Password Confirmation:</label>
|
||||
<ValidationProvider tag="div" class="input-wrapper" name="confirmation" rules="required" vid="confirmation" v-slot="{ errors }">
|
||||
<input v-model="admin.password_confirmation" placeholder="Confirm your password" type="password" :class="{'border-red': errors[0]}" />
|
||||
<input v-model="admin.password_confirmation" placeholder="Confirm your password" type="password" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="submit-wrapper">
|
||||
<AuthButton icon="chevron-right" text="Create Admin and Login" :loading="isLoading" :disabled="isLoading"/>
|
||||
<AuthButton icon="chevron-right" text="Create Admin and Login" :loading="isLoading" :disabled="isLoading" />
|
||||
</div>
|
||||
|
||||
</ValidationObserver>
|
||||
</AuthContent>
|
||||
</AuthContentWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from "../../components/Auth/AuthContentWrapper";
|
||||
import SelectInput from "../../components/Others/Forms/SelectInput";
|
||||
import SwitchInput from "../../components/Others/Forms/SwitchInput";
|
||||
import ImageInput from "../../components/Others/Forms/ImageInput";
|
||||
import FormLabel from "../../components/Others/Forms/FormLabel";
|
||||
import InfoBox from "../../components/Others/Forms/InfoBox";
|
||||
import AuthContent from "../../components/Auth/AuthContent";
|
||||
import AuthButton from "../../components/Auth/AuthButton";
|
||||
import { SettingsIcon } from 'vue-feather-icons'
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {events} from '../../bus'
|
||||
import axios from 'axios'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
|
||||
import SelectInput from '../../components/Others/Forms/SelectInput'
|
||||
import SwitchInput from '../../components/Others/Forms/SwitchInput'
|
||||
import ImageInput from '../../components/Others/Forms/ImageInput'
|
||||
import FormLabel from '../../components/Others/Forms/FormLabel'
|
||||
import InfoBox from '../../components/Others/Forms/InfoBox'
|
||||
import AuthContent from '../../components/Auth/AuthContent'
|
||||
import AuthButton from '../../components/Auth/AuthButton'
|
||||
import { SettingsIcon } from 'vue-feather-icons'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { events } from '../../bus'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'EnvironmentSetup',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SettingsIcon,
|
||||
SelectInput,
|
||||
SwitchInput,
|
||||
AuthContent,
|
||||
ImageInput,
|
||||
AuthButton,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
admin: {
|
||||
name: '',
|
||||
email: '',
|
||||
avatar: undefined,
|
||||
password: '',
|
||||
password_confirmation: '',
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async adminAccountSubmit() {
|
||||
export default {
|
||||
name: 'EnvironmentSetup',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SettingsIcon,
|
||||
SelectInput,
|
||||
SwitchInput,
|
||||
AuthContent,
|
||||
ImageInput,
|
||||
AuthButton,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
admin: {
|
||||
name: '',
|
||||
email: '',
|
||||
avatar: undefined,
|
||||
password: '',
|
||||
password_confirmation: '',
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async adminAccountSubmit() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.adminAccount.validate()
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.adminAccount.validate();
|
||||
if (!isValid) return
|
||||
|
||||
if (!isValid) return;
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
// Create form
|
||||
let formData = new FormData()
|
||||
|
||||
// Create form
|
||||
let formData = new FormData()
|
||||
// Add image to form
|
||||
formData.append('name', this.admin.name)
|
||||
formData.append('email', this.admin.email)
|
||||
formData.append('password', this.admin.password)
|
||||
formData.append('password_confirmation', this.admin.password_confirmation)
|
||||
|
||||
// Add image to form
|
||||
formData.append('name', this.admin.name)
|
||||
formData.append('email', this.admin.email)
|
||||
formData.append('password', this.admin.password)
|
||||
formData.append('password_confirmation', this.admin.password_confirmation)
|
||||
formData.append('license', localStorage.getItem('license'))
|
||||
formData.append('purchase_code', localStorage.getItem('purchase_code'))
|
||||
|
||||
formData.append('license', localStorage.getItem('license'))
|
||||
formData.append('purchase_code', localStorage.getItem('purchase_code'))
|
||||
if (this.admin.avatar) formData.append('avatar', this.admin.avatar)
|
||||
|
||||
if (this.admin.avatar)
|
||||
formData.append('avatar', this.admin.avatar)
|
||||
axios
|
||||
.post('/api/setup/admin-setup', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
axios
|
||||
.post('/api/setup/admin-setup', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
// Set login state
|
||||
this.$store.commit('SET_AUTHORIZED', true)
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
if (localStorage.getItem('license') === 'Extended') {
|
||||
this.$store.commit('SET_SAAS', true)
|
||||
}
|
||||
|
||||
// Set login state
|
||||
this.$store.commit('SET_AUTHORIZED', true)
|
||||
|
||||
if (localStorage.getItem('license') === 'Extended') {
|
||||
this.$store.commit('SET_SAAS', true)
|
||||
}
|
||||
|
||||
// Go to files page
|
||||
this.$router.push({name: 'Dashboard'})
|
||||
|
||||
// Remove license from localStorage
|
||||
localStorage.removeItem('purchase_code')
|
||||
localStorage.removeItem('license')
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
if (error.response.status == 401) {
|
||||
|
||||
if (error.response.data.error === 'invalid_client') {
|
||||
events.$emit('alert:open', {
|
||||
emoji: '🤔',
|
||||
title: this.$t('popup_passport_error.title'),
|
||||
message: this.$t('popup_passport_error.message')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (error.response.status == 500) {
|
||||
// Go to files page
|
||||
this.$router.push({ name: 'Dashboard' })
|
||||
|
||||
// Remove license from localStorage
|
||||
localStorage.removeItem('purchase_code')
|
||||
localStorage.removeItem('license')
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response.status == 401) {
|
||||
if (error.response.data.error === 'invalid_client') {
|
||||
events.$emit('alert:open', {
|
||||
emoji: '🤔',
|
||||
title: this.$t('popup_signup_error.title'),
|
||||
message: this.$t('popup_signup_error.message')
|
||||
title: this.$t('popup_passport_error.title'),
|
||||
message: this.$t('popup_passport_error.message'),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (error.response.status == 500) {
|
||||
events.$emit('alert:open', {
|
||||
emoji: '🤔',
|
||||
title: this.$t('popup_signup_error.title'),
|
||||
message: this.$t('popup_signup_error.message'),
|
||||
})
|
||||
}
|
||||
|
||||
if (error.response.status == 422) {
|
||||
if (error.response.data.errors['email']) {
|
||||
this.$refs.adminAccount.setErrors({
|
||||
Email: error.response.data.errors['email'],
|
||||
})
|
||||
}
|
||||
|
||||
if (error.response.status == 422) {
|
||||
|
||||
if (error.response.data.errors['email']) {
|
||||
|
||||
this.$refs.adminAccount.setErrors({
|
||||
'Email': error.response.data.errors['email']
|
||||
});
|
||||
}
|
||||
|
||||
if (error.response.data.errors['password']) {
|
||||
|
||||
this.$refs.adminAccount.setErrors({
|
||||
'Password': error.response.data.errors['password']
|
||||
});
|
||||
}
|
||||
if (error.response.data.errors['password']) {
|
||||
this.$refs.adminAccount.setErrors({
|
||||
Password: error.response.data.errors['password'],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../../../sass/vuefilemanager/forms';
|
||||
@import '../../../sass/vuefilemanager/auth';
|
||||
@import '../../../sass/vuefilemanager/setup_wizard';
|
||||
@import '../../../sass/vuefilemanager/forms';
|
||||
@import '../../../sass/vuefilemanager/auth';
|
||||
@import '../../../sass/vuefilemanager/setup_wizard';
|
||||
</style>
|
||||
|
||||
@@ -1,24 +1,18 @@
|
||||
<template>
|
||||
<AuthContentWrapper ref="auth">
|
||||
|
||||
<!--Database Credentials-->
|
||||
<AuthContent name="database-credentials" :visible="true">
|
||||
<Headline
|
||||
class="container mx-auto max-w-screen-sm"
|
||||
title="Setup Wizard"
|
||||
description="Set up your application appearance, analytics, etc."
|
||||
>
|
||||
<Headline class="container mx-auto max-w-screen-sm" title="Setup Wizard" description="Set up your application appearance, analytics, etc.">
|
||||
<settings-icon size="40" class="title-icon text-theme mx-auto" />
|
||||
</Headline>
|
||||
</Headline>
|
||||
|
||||
<ValidationObserver @submit.prevent="appSetupSubmit" ref="appSetup" v-slot="{ invalid }" tag="form"
|
||||
class="form block-form">
|
||||
<ValidationObserver @submit.prevent="appSetupSubmit" ref="appSetup" v-slot="{ invalid }" tag="form" class="form block-form">
|
||||
<FormLabel>General Settings</FormLabel>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>App Title:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Title" rules="required" v-slot="{ errors }">
|
||||
<input v-model="app.title" placeholder="Type your app title" type="text" :class="{'border-red': errors[0]}"/>
|
||||
<input v-model="app.title" placeholder="Type your app title" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -26,7 +20,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>App Description:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Description" rules="required" v-slot="{ errors }">
|
||||
<input v-model="app.description" placeholder="Type your app description" type="text" :class="{'border-red': errors[0]}"/>
|
||||
<input v-model="app.description" placeholder="Type your app description" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -34,28 +28,28 @@
|
||||
<div class="block-wrapper">
|
||||
<label>App Logo (optional):</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Logo" v-slot="{ errors }">
|
||||
<ImageInput v-model="app.logo" :error="errors[0]"/>
|
||||
<ImageInput v-model="app.logo" :error="errors[0]" />
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>App Logo Horizontal (optional):</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Logo" v-slot="{ errors }">
|
||||
<ImageInput v-model="app.logo_horizontal" :error="errors[0]"/>
|
||||
<ImageInput v-model="app.logo_horizontal" :error="errors[0]" />
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>App Favicon (optional):</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Favicon" v-slot="{ errors }">
|
||||
<ImageInput v-model="app.favicon" :error="errors[0]"/>
|
||||
<ImageInput v-model="app.favicon" :error="errors[0]" />
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>OG Image (optional):</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Favicon" v-slot="{ errors }">
|
||||
<ImageInput v-model="app.og_image" :error="errors[0]"/>
|
||||
<ImageInput v-model="app.og_image" :error="errors[0]" />
|
||||
<small class="input-help">Image that appear when someone shares the content to Facebook or any other social medium. Preferred size is 1200x627</small>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -63,7 +57,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>App Touch Icon (optional):</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Favicon" v-slot="{ errors }">
|
||||
<ImageInput v-model="app.touch_icon" :error="errors[0]"/>
|
||||
<ImageInput v-model="app.touch_icon" :error="errors[0]" />
|
||||
<small class="input-help">If user store bookmark on his phone screen, this icon appear in app thumbnail. Preferred size is 156x156</small>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -72,19 +66,16 @@
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Contact Email:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Contact Email"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<input v-model="app.contactMail" placeholder="Type your contact email" type="email" :class="{'border-red': errors[0]}"/>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Contact Email" rules="required" v-slot="{ errors }">
|
||||
<input v-model="app.contactMail" placeholder="Type your contact email" type="email" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Google Analytics Code (optional):</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Google Analytics Code"
|
||||
v-slot="{ errors }">
|
||||
<input v-model="app.googleAnalytics" placeholder="Paste your Google Analytics Code"
|
||||
type="text" :class="{'border-red': errors[0]}"/>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Google Analytics Code" v-slot="{ errors }">
|
||||
<input v-model="app.googleAnalytics" placeholder="Paste your Google Analytics Code" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -94,9 +85,11 @@
|
||||
<div class="inline-wrapper">
|
||||
<div class="switch-label">
|
||||
<label class="input-label">Storage Limitation:</label>
|
||||
<small class="input-help">If this value is off, all users will have infinity storage capacity and you won't be able to charge your users for storage plan.</small>
|
||||
<small class="input-help"
|
||||
>If this value is off, all users will have infinity storage capacity and you won't be able to charge your users for storage plan.</small
|
||||
>
|
||||
</div>
|
||||
<SwitchInput v-model="app.storageLimitation" class="switch" :state="app.storageLimitation"/>
|
||||
<SwitchInput v-model="app.storageLimitation" class="switch" :state="app.storageLimitation" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -104,12 +97,13 @@
|
||||
<div class="block-wrapper" v-if="app.storageLimitation">
|
||||
<label>Default Storage Space for Accounts:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Default Storage Space" rules="required" v-slot="{ errors }">
|
||||
<input v-model="app.defaultStorage"
|
||||
min="1"
|
||||
max="999999999"
|
||||
placeholder="Set default storage space in GB"
|
||||
type="number"
|
||||
:class="{'border-red': errors[0]}"
|
||||
<input
|
||||
v-model="app.defaultStorage"
|
||||
min="1"
|
||||
max="999999999"
|
||||
placeholder="Set default storage space in GB"
|
||||
type="number"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
@@ -120,146 +114,137 @@
|
||||
<div class="inline-wrapper">
|
||||
<div class="switch-label">
|
||||
<label class="input-label">Allow User Registration:</label>
|
||||
<small class="input-help">You can disable public registration for new users. You will still able to create new users in administration panel.</small>
|
||||
<small class="input-help"
|
||||
>You can disable public registration for new users. You will still able to create new users in administration panel.</small
|
||||
>
|
||||
</div>
|
||||
<SwitchInput v-model="app.userRegistration" class="switch" :state="app.userRegistration"/>
|
||||
<SwitchInput v-model="app.userRegistration" class="switch" :state="app.userRegistration" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="submit-wrapper">
|
||||
<AuthButton icon="chevron-right" text="Save and Create Admin" :loading="isLoading" :disabled="isLoading"/>
|
||||
<AuthButton icon="chevron-right" text="Save and Create Admin" :loading="isLoading" :disabled="isLoading" />
|
||||
</div>
|
||||
|
||||
</ValidationObserver>
|
||||
</AuthContent>
|
||||
</AuthContentWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from "../../components/Auth/AuthContentWrapper";
|
||||
import SelectInput from "../../components/Others/Forms/SelectInput";
|
||||
import SwitchInput from "../../components/Others/Forms/SwitchInput";
|
||||
import ImageInput from "../../components/Others/Forms/ImageInput";
|
||||
import FormLabel from "../../components/Others/Forms/FormLabel";
|
||||
import InfoBox from "../../components/Others/Forms/InfoBox";
|
||||
import AuthContent from "../../components/Auth/AuthContent";
|
||||
import AuthButton from "../../components/Auth/AuthButton";
|
||||
import {SettingsIcon} from 'vue-feather-icons'
|
||||
import Headline from "../Auth/Headline"
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {mapGetters} from 'vuex'
|
||||
import axios from 'axios'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
|
||||
import SelectInput from '../../components/Others/Forms/SelectInput'
|
||||
import SwitchInput from '../../components/Others/Forms/SwitchInput'
|
||||
import ImageInput from '../../components/Others/Forms/ImageInput'
|
||||
import FormLabel from '../../components/Others/Forms/FormLabel'
|
||||
import InfoBox from '../../components/Others/Forms/InfoBox'
|
||||
import AuthContent from '../../components/Auth/AuthContent'
|
||||
import AuthButton from '../../components/Auth/AuthButton'
|
||||
import { SettingsIcon } from 'vue-feather-icons'
|
||||
import Headline from '../Auth/Headline'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'EnvironmentSetup',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SettingsIcon,
|
||||
SelectInput,
|
||||
SwitchInput,
|
||||
AuthContent,
|
||||
ImageInput,
|
||||
AuthButton,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
Headline,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
app: {
|
||||
title: '',
|
||||
description: '',
|
||||
logo: undefined,
|
||||
logo_horizontal: undefined,
|
||||
favicon: undefined,
|
||||
og_image: undefined,
|
||||
touch_icon: undefined,
|
||||
contactMail: '',
|
||||
googleAnalytics: '',
|
||||
defaultStorage: '5',
|
||||
userRegistration: 1,
|
||||
storageLimitation: 1,
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async appSetupSubmit() {
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.appSetup.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Create form
|
||||
let formData = new FormData()
|
||||
|
||||
// Add image to form
|
||||
formData.append('title', this.app.title)
|
||||
formData.append('description', this.app.description)
|
||||
formData.append('contactMail', this.app.contactMail)
|
||||
formData.append('userRegistration', Boolean(this.app.userRegistration) ? 1 : 0)
|
||||
formData.append('storageLimitation', Boolean(this.app.storageLimitation) ? 1 : 0)
|
||||
|
||||
if (this.app.googleAnalytics)
|
||||
formData.append('googleAnalytics', this.app.googleAnalytics)
|
||||
|
||||
if (this.app.defaultStorage)
|
||||
formData.append('defaultStorage', this.app.defaultStorage)
|
||||
|
||||
if (this.app.logo)
|
||||
formData.append('logo', this.app.logo)
|
||||
|
||||
if (this.app.logo_horizontal)
|
||||
formData.append('logo_horizontal', this.app.logo_horizontal)
|
||||
|
||||
if (this.app.og_image)
|
||||
formData.append('og_image', this.app.og_image)
|
||||
|
||||
if (this.app.touch_icon)
|
||||
formData.append('touch_icon', this.app.touch_icon)
|
||||
|
||||
if (this.app.favicon)
|
||||
formData.append('favicon', this.app.favicon)
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup/app-setup', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
}
|
||||
})
|
||||
.then(response => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
// Redirect to next step
|
||||
this.$router.push({name: 'AdminAccount'})
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
export default {
|
||||
name: 'EnvironmentSetup',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SettingsIcon,
|
||||
SelectInput,
|
||||
SwitchInput,
|
||||
AuthContent,
|
||||
ImageInput,
|
||||
AuthButton,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
Headline,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
app: {
|
||||
title: '',
|
||||
description: '',
|
||||
logo: undefined,
|
||||
logo_horizontal: undefined,
|
||||
favicon: undefined,
|
||||
og_image: undefined,
|
||||
touch_icon: undefined,
|
||||
contactMail: '',
|
||||
googleAnalytics: '',
|
||||
defaultStorage: '5',
|
||||
userRegistration: 1,
|
||||
storageLimitation: 1,
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async appSetupSubmit() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.appSetup.validate()
|
||||
|
||||
if (!isValid) return
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Create form
|
||||
let formData = new FormData()
|
||||
|
||||
// Add image to form
|
||||
formData.append('title', this.app.title)
|
||||
formData.append('description', this.app.description)
|
||||
formData.append('contactMail', this.app.contactMail)
|
||||
formData.append('userRegistration', Boolean(this.app.userRegistration) ? 1 : 0)
|
||||
formData.append('storageLimitation', Boolean(this.app.storageLimitation) ? 1 : 0)
|
||||
|
||||
if (this.app.googleAnalytics) formData.append('googleAnalytics', this.app.googleAnalytics)
|
||||
|
||||
if (this.app.defaultStorage) formData.append('defaultStorage', this.app.defaultStorage)
|
||||
|
||||
if (this.app.logo) formData.append('logo', this.app.logo)
|
||||
|
||||
if (this.app.logo_horizontal) formData.append('logo_horizontal', this.app.logo_horizontal)
|
||||
|
||||
if (this.app.og_image) formData.append('og_image', this.app.og_image)
|
||||
|
||||
if (this.app.touch_icon) formData.append('touch_icon', this.app.touch_icon)
|
||||
|
||||
if (this.app.favicon) formData.append('favicon', this.app.favicon)
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup/app-setup', formData, {
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
})
|
||||
.then((response) => {
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
// Redirect to next step
|
||||
this.$router.push({ name: 'AdminAccount' })
|
||||
})
|
||||
.catch((error) => {
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../../../sass/vuefilemanager/forms';
|
||||
@import '../../../sass/vuefilemanager/auth';
|
||||
@import '../../../sass/vuefilemanager/setup_wizard';
|
||||
@import '../../../sass/vuefilemanager/forms';
|
||||
@import '../../../sass/vuefilemanager/auth';
|
||||
@import '../../../sass/vuefilemanager/setup_wizard';
|
||||
</style>
|
||||
|
||||
@@ -1,35 +1,25 @@
|
||||
<template>
|
||||
<AuthContentWrapper ref="auth">
|
||||
|
||||
<!--Database Credentials-->
|
||||
<AuthContent name="database-credentials" :visible="true">
|
||||
<Headline
|
||||
class="container mx-auto max-w-screen-sm"
|
||||
title="Setup Wizard"
|
||||
description="Set up your billing information."
|
||||
>
|
||||
<Headline class="container mx-auto max-w-screen-sm" title="Setup Wizard" description="Set up your billing information.">
|
||||
<settings-icon size="40" class="title-icon text-theme mx-auto" />
|
||||
</Headline>
|
||||
<ValidationObserver @submit.prevent="billingInformationSubmit" ref="billingInformation" v-slot="{ invalid }"
|
||||
tag="form" class="form block-form">
|
||||
</Headline>
|
||||
<ValidationObserver @submit.prevent="billingInformationSubmit" ref="billingInformation" v-slot="{ invalid }" tag="form" class="form block-form">
|
||||
<FormLabel>Company Information</FormLabel>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Company Name:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Name"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_name" placeholder="Type your company name"
|
||||
type="text" :class="{'border-red': errors[0]}"/>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Name" rules="required" v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_name" placeholder="Type your company name" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>VAT Number:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Vat Number"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_vat_number" placeholder="Type your VAT number"
|
||||
type="text" :class="{'border-red': errors[0]}"/>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Vat Number" rules="required" v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_vat_number" placeholder="Type your VAT number" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -38,19 +28,16 @@
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Billing Country:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Country"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<SelectInput v-model="billingInformation.billing_country" :options="countries" placeholder="Select your billing country" :isError="errors[0]"/>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Country" rules="required" v-slot="{ errors }">
|
||||
<SelectInput v-model="billingInformation.billing_country" :options="countries" placeholder="Select your billing country" :isError="errors[0]" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Billing Address:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Address"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_address" placeholder="Type your billing address"
|
||||
type="text" :class="{'border-red': errors[0]}"/>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Address" rules="required" v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_address" placeholder="Type your billing address" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -58,19 +45,15 @@
|
||||
<div class="wrapper-inline">
|
||||
<div class="block-wrapper">
|
||||
<label>Billing City:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing City"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_city" placeholder="Type your billing city"
|
||||
type="text" :class="{'border-red': errors[0]}"/>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing City" rules="required" v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_city" placeholder="Type your billing city" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<div class="block-wrapper">
|
||||
<label>Billing Postal Code:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Postal Code"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_postal_code"
|
||||
placeholder="Type your billing postal code" type="text" :class="{'border-red': errors[0]}"/>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Postal Code" rules="required" v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_postal_code" placeholder="Type your billing postal code" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -78,116 +61,106 @@
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Billing State:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing State"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_state" placeholder="Type your billing state"
|
||||
type="text" :class="{'border-red': errors[0]}"/>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing State" rules="required" v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_state" placeholder="Type your billing state" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Billing Phone Number (optional):</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Phone Number"
|
||||
v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_phone_number" placeholder="Type your billing phone number"
|
||||
type="text" :class="{'border-red': errors[0]}"/>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Billing Phone Number" v-slot="{ errors }">
|
||||
<input v-model="billingInformation.billing_phone_number" placeholder="Type your billing phone number" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="submit-wrapper">
|
||||
<AuthButton icon="chevron-right" text="Save and Create Plans" :loading="isLoading"
|
||||
:disabled="isLoading"/>
|
||||
<AuthButton icon="chevron-right" text="Save and Create Plans" :loading="isLoading" :disabled="isLoading" />
|
||||
</div>
|
||||
|
||||
</ValidationObserver>
|
||||
</AuthContent>
|
||||
</AuthContentWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from "../../components/Auth/AuthContentWrapper";
|
||||
import SelectInput from "../../components/Others/Forms/SelectInput";
|
||||
import FormLabel from "../../components/Others/Forms/FormLabel";
|
||||
import InfoBox from "../../components/Others/Forms/InfoBox";
|
||||
import AuthContent from "../../components/Auth/AuthContent";
|
||||
import AuthButton from "../../components/Auth/AuthButton";
|
||||
import {SettingsIcon} from 'vue-feather-icons'
|
||||
import Headline from "../Auth/Headline"
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {mapGetters} from 'vuex'
|
||||
import axios from 'axios'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
|
||||
import SelectInput from '../../components/Others/Forms/SelectInput'
|
||||
import FormLabel from '../../components/Others/Forms/FormLabel'
|
||||
import InfoBox from '../../components/Others/Forms/InfoBox'
|
||||
import AuthContent from '../../components/Auth/AuthContent'
|
||||
import AuthButton from '../../components/Auth/AuthButton'
|
||||
import { SettingsIcon } from 'vue-feather-icons'
|
||||
import Headline from '../Auth/Headline'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'BillingsDetail',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SettingsIcon,
|
||||
SelectInput,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
Headline,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['countries']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
billingInformation: {
|
||||
billing_phone_number: '',
|
||||
billing_postal_code: '',
|
||||
billing_vat_number: '',
|
||||
billing_address: '',
|
||||
billing_country: '',
|
||||
billing_state: '',
|
||||
billing_city: '',
|
||||
billing_name: '',
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async billingInformationSubmit() {
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.billingInformation.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup/stripe-billings', this.billingInformation)
|
||||
.then(() => {
|
||||
|
||||
// Redirect to next step
|
||||
this.$router.push({name: 'SubscriptionPlans'})
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
export default {
|
||||
name: 'BillingsDetail',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SettingsIcon,
|
||||
SelectInput,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
Headline,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['countries']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
billingInformation: {
|
||||
billing_phone_number: '',
|
||||
billing_postal_code: '',
|
||||
billing_vat_number: '',
|
||||
billing_address: '',
|
||||
billing_country: '',
|
||||
billing_state: '',
|
||||
billing_city: '',
|
||||
billing_name: '',
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async billingInformationSubmit() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.billingInformation.validate()
|
||||
|
||||
if (!isValid) return
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup/stripe-billings', this.billingInformation)
|
||||
.then(() => {
|
||||
// Redirect to next step
|
||||
this.$router.push({ name: 'SubscriptionPlans' })
|
||||
})
|
||||
.catch((error) => {})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../../../sass/vuefilemanager/forms';
|
||||
@import '../../../sass/vuefilemanager/auth';
|
||||
@import '../../../sass/vuefilemanager/setup_wizard';
|
||||
@import '../../../sass/vuefilemanager/forms';
|
||||
@import '../../../sass/vuefilemanager/auth';
|
||||
@import '../../../sass/vuefilemanager/setup_wizard';
|
||||
</style>
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
<template>
|
||||
<AuthContentWrapper ref="auth">
|
||||
|
||||
<!--Database Credentials-->
|
||||
<AuthContent name="database-credentials" :visible="true">
|
||||
<Headline
|
||||
class="container mx-auto max-w-screen-sm"
|
||||
title="Setup Wizard"
|
||||
description="Set up your database connection to install application database."
|
||||
>
|
||||
<Headline class="container mx-auto max-w-screen-sm" title="Setup Wizard" description="Set up your database connection to install application database.">
|
||||
<settings-icon size="40" class="title-icon text-theme mx-auto" />
|
||||
</Headline>
|
||||
</Headline>
|
||||
|
||||
<ValidationObserver @submit.prevent="databaseCredentialsSubmit" ref="verifyPurchaseCode" v-slot="{ invalid }" tag="form" class="form block-form">
|
||||
<FormLabel>Database Credentials</FormLabel>
|
||||
<InfoBox>
|
||||
<p>We strongly recommend use MySQL or MariaDB database. Create new database, set all privileges and get credentials. For those who use cPanel or Plesk, here is useful resources:</p>
|
||||
<p>
|
||||
We strongly recommend use MySQL or MariaDB database. Create new database, set all privileges and get credentials. For those who use cPanel or Plesk, here is
|
||||
useful resources:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://www.inmotionhosting.com/support/edu/cpanel/create-database-2/" target="_blank">1. cPanel - MySQL Database Wizard</a>
|
||||
@@ -26,7 +24,13 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Connection:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Connection" rules="required" v-slot="{ errors }">
|
||||
<SelectInput v-model="databaseCredentials.connection" :options="connectionList" default="mysql" placeholder="Select your database connection" :isError="errors[0]"/>
|
||||
<SelectInput
|
||||
v-model="databaseCredentials.connection"
|
||||
:options="connectionList"
|
||||
default="mysql"
|
||||
placeholder="Select your database connection"
|
||||
:isError="errors[0]"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -34,7 +38,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Host:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Host" rules="required" v-slot="{ errors }">
|
||||
<input v-model="databaseCredentials.host" placeholder="Type your database host" type="text" :class="{'border-red': errors[0]}" />
|
||||
<input v-model="databaseCredentials.host" placeholder="Type your database host" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -42,7 +46,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Port:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Port" rules="required" v-slot="{ errors }">
|
||||
<input v-model="databaseCredentials.port" placeholder="Type your database port" type="text" :class="{'border-red': errors[0]}" />
|
||||
<input v-model="databaseCredentials.port" placeholder="Type your database port" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -50,7 +54,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Database Name:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Database Name" rules="required" v-slot="{ errors }">
|
||||
<input v-model="databaseCredentials.name" placeholder="Select your database name" type="text" :class="{'border-red': errors[0]}" />
|
||||
<input v-model="databaseCredentials.name" placeholder="Select your database name" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -58,7 +62,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Database Username:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Database Username" rules="required" v-slot="{ errors }">
|
||||
<input v-model="databaseCredentials.username" placeholder="Select your database name" type="text" :class="{'border-red': errors[0]}" />
|
||||
<input v-model="databaseCredentials.username" placeholder="Select your database name" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -66,124 +70,120 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Database Password:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Database Password" rules="required" v-slot="{ errors }">
|
||||
<input v-model="databaseCredentials.password" placeholder="Select your database password" type="text" :class="{'border-red': errors[0]}" />
|
||||
<input v-model="databaseCredentials.password" placeholder="Select your database password" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<InfoBox v-if="isError" type="error" style="margin-bottom: 10px">
|
||||
<p>We couldn't establish database connection. Please double check your database credentials.</p>
|
||||
<br>
|
||||
<br />
|
||||
<p>Detailed error: {{ errorMessage }}</p>
|
||||
</InfoBox>
|
||||
|
||||
<div class="submit-wrapper">
|
||||
<AuthButton icon="chevron-right" :text="submitButtonText" :loading="isLoading" :disabled="isLoading"/>
|
||||
<AuthButton icon="chevron-right" :text="submitButtonText" :loading="isLoading" :disabled="isLoading" />
|
||||
</div>
|
||||
|
||||
</ValidationObserver>
|
||||
</AuthContent>
|
||||
</AuthContentWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from "../../components/Auth/AuthContentWrapper";
|
||||
import SelectInput from "../../components/Others/Forms/SelectInput";
|
||||
import FormLabel from "../../components/Others/Forms/FormLabel";
|
||||
import InfoBox from "../../components/Others/Forms/InfoBox";
|
||||
import AuthContent from "../../components/Auth/AuthContent";
|
||||
import AuthButton from "../../components/Auth/AuthButton";
|
||||
import { SettingsIcon } from 'vue-feather-icons'
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import Headline from "../Auth/Headline"
|
||||
import {mapGetters} from 'vuex'
|
||||
import axios from 'axios'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
|
||||
import SelectInput from '../../components/Others/Forms/SelectInput'
|
||||
import FormLabel from '../../components/Others/Forms/FormLabel'
|
||||
import InfoBox from '../../components/Others/Forms/InfoBox'
|
||||
import AuthContent from '../../components/Auth/AuthContent'
|
||||
import AuthButton from '../../components/Auth/AuthButton'
|
||||
import { SettingsIcon } from 'vue-feather-icons'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import Headline from '../Auth/Headline'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'Database',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SettingsIcon,
|
||||
SelectInput,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
Headline,
|
||||
export default {
|
||||
name: 'Database',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SettingsIcon,
|
||||
SelectInput,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
Headline,
|
||||
},
|
||||
computed: {
|
||||
submitButtonText() {
|
||||
return this.isLoading ? 'Testing and Installing Database' : 'Test Connection and Install Database'
|
||||
},
|
||||
computed: {
|
||||
submitButtonText() {
|
||||
return this.isLoading ? 'Testing and Installing Database' : 'Test Connection and Install Database'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
errorMessage: '',
|
||||
connectionList: [
|
||||
{
|
||||
label: 'MySQL',
|
||||
value: 'mysql',
|
||||
},
|
||||
],
|
||||
databaseCredentials: {
|
||||
connection: 'mysql',
|
||||
host: '',
|
||||
port: '',
|
||||
name: '',
|
||||
username: '',
|
||||
password: '',
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async databaseCredentialsSubmit() {
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.verifyPurchaseCode.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
this.isError = false
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup/database', this.databaseCredentials)
|
||||
.then(response => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
// Redirect to next step
|
||||
this.$router.push({name: 'InstallationDisclaimer'})
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
if (error.response.status = 500) {
|
||||
this.isError = true
|
||||
this.errorMessage = error.response.data.message
|
||||
}
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
errorMessage: '',
|
||||
connectionList: [
|
||||
{
|
||||
label: 'MySQL',
|
||||
value: 'mysql',
|
||||
},
|
||||
],
|
||||
databaseCredentials: {
|
||||
connection: 'mysql',
|
||||
host: '',
|
||||
port: '',
|
||||
name: '',
|
||||
username: '',
|
||||
password: '',
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async databaseCredentialsSubmit() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.verifyPurchaseCode.validate()
|
||||
|
||||
if (!isValid) return
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
this.isError = false
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup/database', this.databaseCredentials)
|
||||
.then((response) => {
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
// Redirect to next step
|
||||
this.$router.push({ name: 'InstallationDisclaimer' })
|
||||
})
|
||||
.catch((error) => {
|
||||
if ((error.response.status = 500)) {
|
||||
this.isError = true
|
||||
this.errorMessage = error.response.data.message
|
||||
}
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../../../sass/vuefilemanager/forms';
|
||||
@import '../../../sass/vuefilemanager/auth';
|
||||
@import '../../../sass/vuefilemanager/setup_wizard';
|
||||
@import '../../../sass/vuefilemanager/forms';
|
||||
@import '../../../sass/vuefilemanager/auth';
|
||||
@import '../../../sass/vuefilemanager/setup_wizard';
|
||||
</style>
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
<template>
|
||||
<AuthContentWrapper ref="auth">
|
||||
|
||||
<!--Database Credentials-->
|
||||
<AuthContent name="database-credentials" :visible="true">
|
||||
<Headline
|
||||
class="container mx-auto max-w-screen-sm"
|
||||
title="Setup Wizard"
|
||||
description="Set up your storage driver and email client."
|
||||
>
|
||||
<Headline class="container mx-auto max-w-screen-sm" title="Setup Wizard" description="Set up your storage driver and email client.">
|
||||
<settings-icon size="40" class="title-icon text-theme mx-auto" />
|
||||
</Headline>
|
||||
</Headline>
|
||||
<ValidationObserver @submit.prevent="EnvironmentSetupSubmit" ref="environmentSetup" v-slot="{ invalid }" tag="form" class="form block-form">
|
||||
<InfoBox>
|
||||
<p>If you don’t know which storage driver set, keep selected <b>'Local Driver'</b>. For more info, where
|
||||
you can host your files <a href="https://vuefilemanager.com/docs/guide/storage.html#introduction" target="_blank">visit our guide</a>.</p>
|
||||
<p>
|
||||
If you don’t know which storage driver set, keep selected <b>'Local Driver'</b>. For more info, where you can host your files
|
||||
<a href="https://vuefilemanager.com/docs/guide/storage.html#introduction" target="_blank">visit our guide</a>.
|
||||
</p>
|
||||
</InfoBox>
|
||||
|
||||
<FormLabel>Storage Setup</FormLabel>
|
||||
@@ -21,7 +18,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Storage Service:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Storage Service" rules="required" v-slot="{ errors }">
|
||||
<SelectInput v-model="storage.driver" :options="storageServiceList" default="local" placeholder="Select your storage service" :isError="errors[0]"/>
|
||||
<SelectInput v-model="storage.driver" :options="storageServiceList" default="local" placeholder="Select your storage service" :isError="errors[0]" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -30,47 +27,46 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Key:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Key" rules="required" v-slot="{ errors }">
|
||||
<input v-model="storage.key" placeholder="Paste your key" type="text" :class="{'border-red': errors[0]}"/>
|
||||
<input v-model="storage.key" placeholder="Paste your key" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<div class="block-wrapper">
|
||||
<label>Secret:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Secret" rules="required" v-slot="{ errors }">
|
||||
<input v-model="storage.secret" placeholder="Paste your secret" type="text" :class="{'border-red': errors[0]}"/>
|
||||
<input v-model="storage.secret" placeholder="Paste your secret" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<div class="block-wrapper">
|
||||
<label>Region:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Region" rules="required" v-slot="{ errors }">
|
||||
<SelectInput v-model="storage.region" :options="regionList" :key="storage.driver" placeholder="Select your region" :isError="errors[0]"/>
|
||||
<SelectInput v-model="storage.region" :options="regionList" :key="storage.driver" placeholder="Select your region" :isError="errors[0]" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
<small class="input-help">
|
||||
Select your region where is your bucket/space created.
|
||||
</small>
|
||||
<small class="input-help"> Select your region where is your bucket/space created. </small>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<div class="block-wrapper" v-if="storage.driver !== 's3'">
|
||||
<label>Endpoint URL:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Endpoint" rules="required" v-slot="{ errors }">
|
||||
<input v-model="storage.endpoint" placeholder="Type your endpoint" type="text" :class="{'border-red': errors[0]}" readonly/>
|
||||
<input v-model="storage.endpoint" placeholder="Type your endpoint" type="text" :class="{ 'border-red': errors[0] }" readonly />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
<div class="block-wrapper">
|
||||
<label>Bucket:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Bucket" rules="required" v-slot="{ errors }">
|
||||
<input v-model="storage.bucket" placeholder="Type your bucket name" type="text" :class="{'border-red': errors[0]}"/>
|
||||
<input v-model="storage.bucket" placeholder="Type your bucket name" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
<small class="input-help">
|
||||
Provide your created unique bucket name
|
||||
</small>
|
||||
<small class="input-help"> Provide your created unique bucket name </small>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<InfoBox>
|
||||
<p>Later, you can edit these data in your <b>.env</b> file which is located in app root folder.</p>
|
||||
<p>
|
||||
Later, you can edit these data in your
|
||||
<b>.env</b> file which is located in app root folder.
|
||||
</p>
|
||||
</InfoBox>
|
||||
</div>
|
||||
|
||||
@@ -79,7 +75,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Mail Driver:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Mail Driver" rules="required" v-slot="{ errors }">
|
||||
<SelectInput v-model="mail.driver" :options="mailDriverList" default="smtp" placeholder="Select your mail driver" :isError="errors[0]"/>
|
||||
<SelectInput v-model="mail.driver" :options="mailDriverList" default="smtp" placeholder="Select your mail driver" :isError="errors[0]" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -87,7 +83,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Mail Host:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Mail Host" rules="required" v-slot="{ errors }">
|
||||
<input v-model="mail.host" placeholder="Type your mail host" type="text" :class="{'border-red': errors[0]}"/>
|
||||
<input v-model="mail.host" placeholder="Type your mail host" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -95,7 +91,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Mail Port:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Mail Port" rules="required" v-slot="{ errors }">
|
||||
<input v-model="mail.port" placeholder="Type your mail port" type="text" :class="{'border-red': errors[0]}"/>
|
||||
<input v-model="mail.port" placeholder="Type your mail port" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -103,7 +99,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Mail Username:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Mail Username" rules="required" v-slot="{ errors }">
|
||||
<input v-model="mail.username" placeholder="Type your mail username" type="text" :class="{'border-red': errors[0]}"/>
|
||||
<input v-model="mail.username" placeholder="Type your mail username" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -111,7 +107,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Mail Password:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Mail Password" rules="required" v-slot="{ errors }">
|
||||
<input v-model="mail.password" placeholder="Type your mail password" type="text" :class="{'border-red': errors[0]}"/>
|
||||
<input v-model="mail.password" placeholder="Type your mail password" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -119,32 +115,31 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Mail Encryption:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Mail Encryption" rules="required" v-slot="{ errors }">
|
||||
<SelectInput v-model="mail.encryption" :options="encryptionList" placeholder="Select your mail encryption" :isError="errors[0]"/>
|
||||
<SelectInput v-model="mail.encryption" :options="encryptionList" placeholder="Select your mail encryption" :isError="errors[0]" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="submit-wrapper">
|
||||
<AuthButton icon="chevron-right" text="Save and Set General Settings" :loading="isLoading" :disabled="isLoading"/>
|
||||
<AuthButton icon="chevron-right" text="Save and Set General Settings" :loading="isLoading" :disabled="isLoading" />
|
||||
</div>
|
||||
|
||||
</ValidationObserver>
|
||||
</AuthContent>
|
||||
</AuthContentWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from "../../components/Auth/AuthContentWrapper";
|
||||
import SelectInput from "../../components/Others/Forms/SelectInput";
|
||||
import FormLabel from "../../components/Others/Forms/FormLabel";
|
||||
import InfoBox from "../../components/Others/Forms/InfoBox";
|
||||
import AuthContent from "../../components/Auth/AuthContent";
|
||||
import AuthButton from "../../components/Auth/AuthButton";
|
||||
import {SettingsIcon} from 'vue-feather-icons'
|
||||
import Headline from "../Auth/Headline"
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {mapGetters} from 'vuex'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
|
||||
import SelectInput from '../../components/Others/Forms/SelectInput'
|
||||
import FormLabel from '../../components/Others/Forms/FormLabel'
|
||||
import InfoBox from '../../components/Others/Forms/InfoBox'
|
||||
import AuthContent from '../../components/Auth/AuthContent'
|
||||
import AuthButton from '../../components/Auth/AuthButton'
|
||||
import { SettingsIcon } from 'vue-feather-icons'
|
||||
import Headline from '../Auth/Headline'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
@@ -160,24 +155,20 @@ export default {
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
Headline,
|
||||
Headline,
|
||||
},
|
||||
watch: {
|
||||
'storage.driver': function () {
|
||||
this.storage.region = ''
|
||||
},
|
||||
'storage.region': function (val) {
|
||||
if (this.storage.driver === 'spaces')
|
||||
this.storage.endpoint = 'https://' + val + '.digitaloceanspaces.com'
|
||||
if (this.storage.driver === 'spaces') this.storage.endpoint = 'https://' + val + '.digitaloceanspaces.com'
|
||||
|
||||
if (this.storage.driver === 'wasabi')
|
||||
this.storage.endpoint = 'https://s3.' + val + '.wasabisys.com'
|
||||
if (this.storage.driver === 'wasabi') this.storage.endpoint = 'https://s3.' + val + '.wasabisys.com'
|
||||
|
||||
if (this.storage.driver === 'backblaze')
|
||||
this.storage.endpoint = 'https://s3.' + val + '.backblazeb2.com'
|
||||
if (this.storage.driver === 'backblaze') this.storage.endpoint = 'https://s3.' + val + '.backblazeb2.com'
|
||||
|
||||
if (this.storage.driver === 'oss')
|
||||
this.storage.endpoint = 'https://' + val + '.aliyuncs.com'
|
||||
if (this.storage.driver === 'oss') this.storage.endpoint = 'https://' + val + '.aliyuncs.com'
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
@@ -195,65 +186,65 @@ export default {
|
||||
case 'backblaze':
|
||||
return this.backblazeRegions
|
||||
break
|
||||
case 'oss':
|
||||
return this.ossRegions
|
||||
break
|
||||
case 'oss':
|
||||
return this.ossRegions
|
||||
break
|
||||
}
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
ossRegions: [
|
||||
{
|
||||
label: 'China (Hangzhou)',
|
||||
value: 'oss-cn-hangzhou',
|
||||
},
|
||||
{
|
||||
label: 'China (Shanghai)',
|
||||
value: 'oss-cn-shanghai',
|
||||
},
|
||||
{
|
||||
label: 'China (Qingdao)',
|
||||
value: 'oss-cn-qingdao',
|
||||
},
|
||||
{
|
||||
label: 'China (Beijing)',
|
||||
value: 'oss-cn-beijing',
|
||||
},
|
||||
{
|
||||
label: 'China (Zhangjiakou)',
|
||||
value: 'oss-cn-zhangjiakou',
|
||||
},
|
||||
{
|
||||
label: 'China (Hohhot)',
|
||||
value: 'oss-cn-huhehaote',
|
||||
},
|
||||
{
|
||||
label: 'China (Ulanqab)',
|
||||
value: 'oss-cn-wulanchabu',
|
||||
},
|
||||
{
|
||||
label: 'China (Shenzhen)',
|
||||
value: 'oss-cn-shenzhen',
|
||||
},
|
||||
{
|
||||
label: 'China (Heyuan)',
|
||||
value: 'oss-cn-heyuan',
|
||||
},
|
||||
{
|
||||
label: 'China (Guangzhou)',
|
||||
value: 'oss-cn-guangzhou',
|
||||
},
|
||||
{
|
||||
label: 'China (Chengdu)',
|
||||
value: 'oss-cn-chengdu',
|
||||
},
|
||||
{
|
||||
label: 'China (Hong Kong)',
|
||||
value: 'oss-cn-hongkong',
|
||||
},
|
||||
],
|
||||
ossRegions: [
|
||||
{
|
||||
label: 'China (Hangzhou)',
|
||||
value: 'oss-cn-hangzhou',
|
||||
},
|
||||
{
|
||||
label: 'China (Shanghai)',
|
||||
value: 'oss-cn-shanghai',
|
||||
},
|
||||
{
|
||||
label: 'China (Qingdao)',
|
||||
value: 'oss-cn-qingdao',
|
||||
},
|
||||
{
|
||||
label: 'China (Beijing)',
|
||||
value: 'oss-cn-beijing',
|
||||
},
|
||||
{
|
||||
label: 'China (Zhangjiakou)',
|
||||
value: 'oss-cn-zhangjiakou',
|
||||
},
|
||||
{
|
||||
label: 'China (Hohhot)',
|
||||
value: 'oss-cn-huhehaote',
|
||||
},
|
||||
{
|
||||
label: 'China (Ulanqab)',
|
||||
value: 'oss-cn-wulanchabu',
|
||||
},
|
||||
{
|
||||
label: 'China (Shenzhen)',
|
||||
value: 'oss-cn-shenzhen',
|
||||
},
|
||||
{
|
||||
label: 'China (Heyuan)',
|
||||
value: 'oss-cn-heyuan',
|
||||
},
|
||||
{
|
||||
label: 'China (Guangzhou)',
|
||||
value: 'oss-cn-guangzhou',
|
||||
},
|
||||
{
|
||||
label: 'China (Chengdu)',
|
||||
value: 'oss-cn-chengdu',
|
||||
},
|
||||
{
|
||||
label: 'China (Hong Kong)',
|
||||
value: 'oss-cn-hongkong',
|
||||
},
|
||||
],
|
||||
wasabiRegions: [
|
||||
{
|
||||
label: 'US East 1 (N. Virginia)',
|
||||
@@ -411,10 +402,10 @@ export default {
|
||||
label: 'Backblaze B2 Cloud Storage',
|
||||
value: 'backblaze',
|
||||
},
|
||||
{
|
||||
label: 'Alibaba Cloud OSS',
|
||||
value: 'oss',
|
||||
},
|
||||
{
|
||||
label: 'Alibaba Cloud OSS',
|
||||
value: 'oss',
|
||||
},
|
||||
],
|
||||
encryptionList: [
|
||||
{
|
||||
@@ -471,16 +462,15 @@ export default {
|
||||
username: '',
|
||||
password: '',
|
||||
encryption: '',
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async EnvironmentSetupSubmit() {
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.environmentSetup.validate();
|
||||
const isValid = await this.$refs.environmentSetup.validate()
|
||||
|
||||
if (!isValid) return;
|
||||
if (!isValid) return
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
@@ -491,16 +481,14 @@ export default {
|
||||
storage: this.storage,
|
||||
mail: this.mail,
|
||||
})
|
||||
.then(response => {
|
||||
|
||||
.then((response) => {
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
// Redirect to next step
|
||||
this.$router.push({name: 'AppSetup'})
|
||||
this.$router.push({ name: 'AppSetup' })
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
.catch((error) => {
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
@@ -508,7 +496,7 @@ export default {
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -1,66 +1,43 @@
|
||||
<template>
|
||||
<AuthContentWrapper ref="auth">
|
||||
|
||||
<!--Database Credentials-->
|
||||
<AuthContent name="database-credentials" :visible="true">
|
||||
<Headline
|
||||
class="container mx-auto max-w-screen-sm"
|
||||
title="Setup Wizard"
|
||||
description="Database was installed successfully. Let's set up application, Make sure you have these informations before continue:"
|
||||
>
|
||||
<Headline
|
||||
class="container mx-auto max-w-screen-sm"
|
||||
title="Setup Wizard"
|
||||
description="Database was installed successfully. Let's set up application, Make sure you have these informations before continue:"
|
||||
>
|
||||
<settings-icon size="40" class="title-icon text-theme mx-auto" />
|
||||
</Headline>
|
||||
</Headline>
|
||||
<div id="loader" v-if="isLoading">
|
||||
<Spinner></Spinner>
|
||||
</div>
|
||||
|
||||
<div class="form block-form" v-if="! isLoading">
|
||||
<div class="form block-form" v-if="!isLoading">
|
||||
<InfoBox>
|
||||
<ul v-if="isExtended" style="margin-top: 0" class="information-list">
|
||||
<li>
|
||||
1. Stripe API Credentials
|
||||
</li>
|
||||
<li>
|
||||
2. Billing details for Stripe Subscription Service
|
||||
</li>
|
||||
<li>
|
||||
3. You will create your subscription plans
|
||||
</li>
|
||||
<li>
|
||||
4. Email Account Credentials for sending emails to your users
|
||||
</li>
|
||||
<li>
|
||||
5. If you use external storage service, then you will need set your API credentials
|
||||
</li>
|
||||
<li>
|
||||
6. Some general settings for VueFileManager like Google Analytics, logo, favicon and application name
|
||||
</li>
|
||||
<li>
|
||||
7. You will create admin account
|
||||
</li>
|
||||
<li>1. Stripe API Credentials</li>
|
||||
<li>2. Billing details for Stripe Subscription Service</li>
|
||||
<li>3. You will create your subscription plans</li>
|
||||
<li>4. Email Account Credentials for sending emails to your users</li>
|
||||
<li>5. If you use external storage service, then you will need set your API credentials</li>
|
||||
<li>6. Some general settings for VueFileManager like Google Analytics, logo, favicon and application name</li>
|
||||
<li>7. You will create admin account</li>
|
||||
</ul>
|
||||
<ul v-else style="margin-top: 0" class="information-list">
|
||||
<li>
|
||||
1. Email Account Credentials for sending emails to your users
|
||||
</li>
|
||||
<li>
|
||||
2. If you use external storage service, then you will need set your API credentials
|
||||
</li>
|
||||
<li>
|
||||
3. Some general settings for VueFileManager like Google Analytics, logo, favicon and application name
|
||||
</li>
|
||||
<li>
|
||||
4. You will create admin account
|
||||
</li>
|
||||
<li>1. Email Account Credentials for sending emails to your users</li>
|
||||
<li>2. If you use external storage service, then you will need set your API credentials</li>
|
||||
<li>3. Some general settings for VueFileManager like Google Analytics, logo, favicon and application name</li>
|
||||
<li>4. You will create admin account</li>
|
||||
</ul>
|
||||
</InfoBox>
|
||||
|
||||
<router-link v-if="isExtended" :to="{name: 'SubscriptionService'}" tag="div" class="submit-wrapper">
|
||||
<AuthButton icon="chevron-right" text="I Get It! Let's Set Up Application" :loading="isLoading" :disabled="isLoading"/>
|
||||
<router-link v-if="isExtended" :to="{ name: 'SubscriptionService' }" tag="div" class="submit-wrapper">
|
||||
<AuthButton icon="chevron-right" text="I Get It! Let's Set Up Application" :loading="isLoading" :disabled="isLoading" />
|
||||
</router-link>
|
||||
|
||||
<router-link v-if="! isExtended" :to="{name: 'EnvironmentSetup'}" tag="div" class="submit-wrapper">
|
||||
<AuthButton icon="chevron-right" text="I Get It! Let's Set Up Application" :loading="isLoading" :disabled="isLoading"/>
|
||||
<router-link v-if="!isExtended" :to="{ name: 'EnvironmentSetup' }" tag="div" class="submit-wrapper">
|
||||
<AuthButton icon="chevron-right" text="I Get It! Let's Set Up Application" :loading="isLoading" :disabled="isLoading" />
|
||||
</router-link>
|
||||
</div>
|
||||
</AuthContent>
|
||||
@@ -68,101 +45,98 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from "../../components/Auth/AuthContentWrapper";
|
||||
import SelectInput from "../../components/Others/Forms/SelectInput";
|
||||
import FormLabel from "../../components/Others/Forms/FormLabel";
|
||||
import InfoBox from "../../components/Others/Forms/InfoBox";
|
||||
import AuthContent from "../../components/Auth/AuthContent";
|
||||
import AuthButton from "../../components/Auth/AuthButton";
|
||||
import Spinner from "../../components/FilesView/Spinner";
|
||||
import { SettingsIcon } from 'vue-feather-icons'
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import Headline from "../Auth/Headline"
|
||||
import {mapGetters} from 'vuex'
|
||||
import axios from 'axios'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
|
||||
import SelectInput from '../../components/Others/Forms/SelectInput'
|
||||
import FormLabel from '../../components/Others/Forms/FormLabel'
|
||||
import InfoBox from '../../components/Others/Forms/InfoBox'
|
||||
import AuthContent from '../../components/Auth/AuthContent'
|
||||
import AuthButton from '../../components/Auth/AuthButton'
|
||||
import Spinner from '../../components/FilesView/Spinner'
|
||||
import { SettingsIcon } from 'vue-feather-icons'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import Headline from '../Auth/Headline'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'InstallationDisclaimer',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SettingsIcon,
|
||||
SelectInput,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
FormLabel,
|
||||
required,
|
||||
Spinner,
|
||||
InfoBox,
|
||||
Headline,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
isError: false,
|
||||
isExtended: undefined
|
||||
}
|
||||
},
|
||||
created() {
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup/purchase-code', {
|
||||
purchaseCode: localStorage.getItem('purchase_code'),
|
||||
})
|
||||
.then(response => {
|
||||
|
||||
this.$scrollTop()
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
if (response.data === 'b6896a44017217c36f4a6fdc56699728') {
|
||||
this.isExtended = true
|
||||
localStorage.setItem('license', 'Extended')
|
||||
} else {
|
||||
this.isExtended = false
|
||||
localStorage.setItem('license', 'Regular')
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
if (error.response.status == 400) {
|
||||
this.$router.push({name: 'PurchaseCode'})
|
||||
}
|
||||
})
|
||||
export default {
|
||||
name: 'InstallationDisclaimer',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SettingsIcon,
|
||||
SelectInput,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
FormLabel,
|
||||
required,
|
||||
Spinner,
|
||||
InfoBox,
|
||||
Headline,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
isError: false,
|
||||
isExtended: undefined,
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup/purchase-code', {
|
||||
purchaseCode: localStorage.getItem('purchase_code'),
|
||||
})
|
||||
.then((response) => {
|
||||
this.$scrollTop()
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
if (response.data === 'b6896a44017217c36f4a6fdc56699728') {
|
||||
this.isExtended = true
|
||||
localStorage.setItem('license', 'Extended')
|
||||
} else {
|
||||
this.isExtended = false
|
||||
localStorage.setItem('license', 'Regular')
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
if (error.response.status == 400) {
|
||||
this.$router.push({ name: 'PurchaseCode' })
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../../../sass/vuefilemanager/forms';
|
||||
@import '../../../sass/vuefilemanager/auth';
|
||||
@import '../../../sass/vuefilemanager/setup_wizard';
|
||||
@import '../../../sass/vuefilemanager/forms';
|
||||
@import '../../../sass/vuefilemanager/auth';
|
||||
@import '../../../sass/vuefilemanager/setup_wizard';
|
||||
|
||||
#loader {
|
||||
position: relative;
|
||||
margin-top: 80px;
|
||||
}
|
||||
#loader {
|
||||
position: relative;
|
||||
margin-top: 80px;
|
||||
}
|
||||
|
||||
.information-list {
|
||||
li {
|
||||
padding: 8px 0;
|
||||
@include font-size(17);
|
||||
font-weight: 600;
|
||||
.information-list {
|
||||
li {
|
||||
padding: 8px 0;
|
||||
@include font-size(17);
|
||||
font-weight: 600;
|
||||
|
||||
&:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
&:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
&:last-child {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,139 +1,124 @@
|
||||
<template>
|
||||
<AuthContentWrapper ref="auth">
|
||||
|
||||
<!--Licence Verify-->
|
||||
<AuthContent name="licence-verify" :visible="true">
|
||||
|
||||
<Headline
|
||||
class="container mx-auto max-w-screen-sm"
|
||||
title="Setup Wizard"
|
||||
description="Please set your purchase code before continue to set up your application."
|
||||
>
|
||||
<Headline class="container mx-auto max-w-screen-sm" title="Setup Wizard" description="Please set your purchase code before continue to set up your application.">
|
||||
<settings-icon size="40" class="title-icon text-theme mx-auto" />
|
||||
</Headline>
|
||||
</Headline>
|
||||
|
||||
<ValidationObserver @submit.prevent="verifyPurchaseCode" ref="verifyPurchaseCode" v-slot="{ invalid }" tag="form" class="form inline-form">
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Purchase Code" rules="required" v-slot="{ errors }">
|
||||
<input v-model="purchaseCode" placeholder="Paste your purchase code" type="text" :class="{'border-red': errors[0]}"/>
|
||||
<input v-model="purchaseCode" placeholder="Paste your purchase code" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
<AuthButton icon="chevron-right" text="Verify" :loading="isLoading" :disabled="isLoading"/>
|
||||
<AuthButton icon="chevron-right" text="Verify" :loading="isLoading" :disabled="isLoading" />
|
||||
</ValidationObserver>
|
||||
|
||||
<p class="additional-link">
|
||||
<a href="https://help.market.envato.com/hc/en-us/articles/202822600-Where-Is-My-Purchase-Code-" target="_blank">
|
||||
Where I can find purchase code?
|
||||
</a>
|
||||
<a class="black-link" href="https://codecanyon.net/item/vue-file-manager-with-laravel-backend/25815986" target="_blank">
|
||||
Don’t have purchase code?
|
||||
</a>
|
||||
<a href="https://help.market.envato.com/hc/en-us/articles/202822600-Where-Is-My-Purchase-Code-" target="_blank"> Where I can find purchase code? </a>
|
||||
<a class="black-link" href="https://codecanyon.net/item/vue-file-manager-with-laravel-backend/25815986" target="_blank"> Don’t have purchase code? </a>
|
||||
</p>
|
||||
</AuthContent>
|
||||
</AuthContentWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AuthContentWrapper from "../../components/Auth/AuthContentWrapper";
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import InfoBox from "../../components/Others/Forms/InfoBox";
|
||||
import AuthContent from "../../components/Auth/AuthContent";
|
||||
import AuthButton from "../../components/Auth/AuthButton";
|
||||
import { SettingsIcon } from 'vue-feather-icons'
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import Headline from "../Auth/Headline"
|
||||
import {mapGetters} from 'vuex'
|
||||
import axios from 'axios'
|
||||
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import InfoBox from '../../components/Others/Forms/InfoBox'
|
||||
import AuthContent from '../../components/Auth/AuthContent'
|
||||
import AuthButton from '../../components/Auth/AuthButton'
|
||||
import { SettingsIcon } from 'vue-feather-icons'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import Headline from '../Auth/Headline'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'PurchaseCode',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SettingsIcon,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
required,
|
||||
InfoBox,
|
||||
Headline,
|
||||
export default {
|
||||
name: 'PurchaseCode',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SettingsIcon,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
required,
|
||||
InfoBox,
|
||||
Headline,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
purchaseCode: '',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async verifyPurchaseCode() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.verifyPurchaseCode.validate()
|
||||
|
||||
if (!isValid) return
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup/purchase-code', {
|
||||
purchaseCode: this.purchaseCode,
|
||||
})
|
||||
.then((response) => {
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
localStorage.setItem('purchase_code', this.purchaseCode)
|
||||
|
||||
// Redirect to next step
|
||||
this.$router.push({ name: 'Database' })
|
||||
})
|
||||
.catch((error) => {
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
if (error.response.status == 400) {
|
||||
this.$refs.verifyPurchaseCode.setErrors({
|
||||
'Purchase Code': ['Purchase code is invalid.'],
|
||||
})
|
||||
} else if (error.response.status == 404) {
|
||||
this.$refs.verifyPurchaseCode.setErrors({
|
||||
'Purchase Code': ['You may have misconfigured the app, please read the readme file and try it again.'],
|
||||
})
|
||||
} else {
|
||||
this.$refs.verifyPurchaseCode.setErrors({
|
||||
'Purchase Code': ['Something is wrong. Please try again.'],
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
purchaseCode: '',
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async verifyPurchaseCode() {
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.verifyPurchaseCode.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup/purchase-code', {
|
||||
purchaseCode: this.purchaseCode,
|
||||
})
|
||||
.then(response => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
localStorage.setItem('purchase_code', this.purchaseCode)
|
||||
|
||||
// Redirect to next step
|
||||
this.$router.push({name: 'Database'})
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
if (error.response.status == 400) {
|
||||
this.$refs.verifyPurchaseCode.setErrors({
|
||||
'Purchase Code': ['Purchase code is invalid.']
|
||||
});
|
||||
} else if (error.response.status == 404) {
|
||||
this.$refs.verifyPurchaseCode.setErrors({
|
||||
'Purchase Code': ['You may have misconfigured the app, please read the readme file and try it again.']
|
||||
});
|
||||
} else {
|
||||
this.$refs.verifyPurchaseCode.setErrors({
|
||||
'Purchase Code': ['Something is wrong. Please try again.']
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../../../sass/vuefilemanager/auth';
|
||||
@import '../../../sass/vuefilemanager/setup_wizard';
|
||||
@import '../../../sass/vuefilemanager/auth';
|
||||
@import '../../../sass/vuefilemanager/setup_wizard';
|
||||
|
||||
.additional-link {
|
||||
.black-link {
|
||||
color: $text;
|
||||
}
|
||||
}
|
||||
|
||||
.auth-form input {
|
||||
min-width: 380px;
|
||||
}
|
||||
|
||||
.dark {
|
||||
.additional-link {
|
||||
|
||||
.black-link {
|
||||
color: $text;
|
||||
}
|
||||
}
|
||||
|
||||
.auth-form input {
|
||||
min-width: 380px;
|
||||
}
|
||||
|
||||
.dark {
|
||||
.additional-link {
|
||||
|
||||
.black-link {
|
||||
color: $dark_mode_text_primary;
|
||||
}
|
||||
color: $dark_mode_text_primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,95 +1,92 @@
|
||||
<template>
|
||||
<AuthContentWrapper ref="auth">
|
||||
|
||||
<!--Database Credentials-->
|
||||
<AuthContent name="database-credentials" :visible="true">
|
||||
|
||||
<Headline
|
||||
class="container mx-auto max-w-screen-sm"
|
||||
title="Server Check"
|
||||
description="At first, we have to check if all modules and setup is ready for running VueFileManager"
|
||||
>
|
||||
<Headline
|
||||
class="container mx-auto max-w-screen-sm"
|
||||
title="Server Check"
|
||||
description="At first, we have to check if all modules and setup is ready for running VueFileManager"
|
||||
>
|
||||
<settings-icon size="40" class="title-icon text-theme mx-auto" />
|
||||
</Headline>
|
||||
</Headline>
|
||||
|
||||
<div class="form block-form">
|
||||
|
||||
<!--PHP Extension info-->
|
||||
<!--PHP Extension info-->
|
||||
<FormLabel>Required PHP Extensions</FormLabel>
|
||||
<InfoBox>
|
||||
<p>Those PHP modules are needed for accurate running VueFileManager on your server, please check and install if some is missing.</p>
|
||||
</InfoBox>
|
||||
|
||||
<ul v-if="modules" class="check-list">
|
||||
<li v-for="(value, module, i) in modules" :key="i" class="check-item">
|
||||
<div class="content">
|
||||
<b class="parameter capitalize">{{ module }}</b>
|
||||
</div>
|
||||
<div class="status" :class="value ? 'success' : 'danger'">
|
||||
<check-icon v-if="value" size="16" />
|
||||
<x-icon v-if="! value" size="16" />
|
||||
<span class="note">{{ value ? 'Module Installed' : 'Missing Module' }}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<ul v-if="modules" class="check-list">
|
||||
<li v-for="(value, module, i) in modules" :key="i" class="check-item">
|
||||
<div class="content">
|
||||
<b class="parameter capitalize">{{ module }}</b>
|
||||
</div>
|
||||
<div class="status" :class="value ? 'success' : 'danger'">
|
||||
<check-icon v-if="value" size="16" />
|
||||
<x-icon v-if="!value" size="16" />
|
||||
<span class="note">{{ value ? 'Module Installed' : 'Missing Module' }}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!--PHP version and ini check-->
|
||||
<!--PHP version and ini check-->
|
||||
<FormLabel>PHP Version and php.ini</FormLabel>
|
||||
<InfoBox>
|
||||
<p>Those PHP settings are needed for accurate running VueFileManager on your server, please check and tweak in your php.ini if needed.</p>
|
||||
</InfoBox>
|
||||
|
||||
<ul class="check-list">
|
||||
<li class="check-item">
|
||||
<div class="content">
|
||||
<b class="parameter">PHP Version</b>
|
||||
<small v-if="! phpVersion.acceptable" class="help">You need PHP version at least {{ phpVersion.minimal }}.</small>
|
||||
</div>
|
||||
<div class="status" :class="phpVersion.acceptable ? 'success' : 'danger'">
|
||||
<check-icon v-if="phpVersion.acceptable" size="16" />
|
||||
<x-icon v-if="! phpVersion.acceptable" size="16" />
|
||||
<span class="note">{{ phpVersion.current }}</span>
|
||||
</div>
|
||||
</li>
|
||||
<ul class="check-list">
|
||||
<li class="check-item">
|
||||
<div class="content">
|
||||
<b class="parameter">PHP Version</b>
|
||||
<small v-if="!phpVersion.acceptable" class="help">You need PHP version at least {{ phpVersion.minimal }}.</small>
|
||||
</div>
|
||||
<div class="status" :class="phpVersion.acceptable ? 'success' : 'danger'">
|
||||
<check-icon v-if="phpVersion.acceptable" size="16" />
|
||||
<x-icon v-if="!phpVersion.acceptable" size="16" />
|
||||
<span class="note">{{ phpVersion.current }}</span>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li v-for="(values, setting, i) in ini" :key="i" class="check-item">
|
||||
<div class="content">
|
||||
<b class="parameter">{{ setting }}</b>
|
||||
<small v-if="! values.status" class="help">We recommend set this value at least {{ values.minimal }}.</small>
|
||||
</div>
|
||||
<div class="status" :class="values.status ? 'success' : 'danger'">
|
||||
<check-icon v-if="values.status" size="16" />
|
||||
<x-icon v-if="! values.status" size="16" />
|
||||
<span class="note">{{ values.current }}{{ setting !== 'max_execution_time' ? 'M' : '' }}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<li v-for="(values, setting, i) in ini" :key="i" class="check-item">
|
||||
<div class="content">
|
||||
<b class="parameter">{{ setting }}</b>
|
||||
<small v-if="!values.status" class="help">We recommend set this value at least {{ values.minimal }}.</small>
|
||||
</div>
|
||||
<div class="status" :class="values.status ? 'success' : 'danger'">
|
||||
<check-icon v-if="values.status" size="16" />
|
||||
<x-icon v-if="!values.status" size="16" />
|
||||
<span class="note">{{ values.current }}{{ setting !== 'max_execution_time' ? 'M' : '' }}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!--API check-->
|
||||
<FormLabel>API</FormLabel>
|
||||
<!--API check-->
|
||||
<FormLabel>API</FormLabel>
|
||||
<InfoBox>
|
||||
<p>The check, if your domain is set correctly.</p>
|
||||
</InfoBox>
|
||||
|
||||
<ul class="check-list">
|
||||
<li class="check-item">
|
||||
<div class="content">
|
||||
<b class="parameter">API</b>
|
||||
<small v-if="isCheckedAPI && ! apiRunning" class="help">We detect, your domain root is not set correctly, please check it.</small>
|
||||
</div>
|
||||
<div v-if="isCheckedAPI" class="status" :class="apiRunning ? 'success' : 'danger'">
|
||||
<check-icon v-if="apiRunning" size="16" />
|
||||
<x-icon v-if="! apiRunning" size="16" />
|
||||
<span class="note">{{ apiRunning ? 'Working correctly' : "Doesn't work" }}</span>
|
||||
</div>
|
||||
<div v-if="! isCheckedAPI" class="status">
|
||||
<span class="note">Checking your API...</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="check-list">
|
||||
<li class="check-item">
|
||||
<div class="content">
|
||||
<b class="parameter">API</b>
|
||||
<small v-if="isCheckedAPI && !apiRunning" class="help">We detect, your domain root is not set correctly, please check it.</small>
|
||||
</div>
|
||||
<div v-if="isCheckedAPI" class="status" :class="apiRunning ? 'success' : 'danger'">
|
||||
<check-icon v-if="apiRunning" size="16" />
|
||||
<x-icon v-if="!apiRunning" size="16" />
|
||||
<span class="note">{{ apiRunning ? 'Working correctly' : "Doesn't work" }}</span>
|
||||
</div>
|
||||
<div v-if="!isCheckedAPI" class="status">
|
||||
<span class="note">Checking your API...</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<InfoBox v-if="isError" type="error" style="margin-bottom: 10px">
|
||||
<p>We can't proceed to the next step because there are unresolved issues. Please solve it at first and next continue.</p>
|
||||
<p>We can't proceed to the next step because there are unresolved issues. Please solve it at first and next continue.</p>
|
||||
</InfoBox>
|
||||
|
||||
<div class="submit-wrapper">
|
||||
@@ -101,162 +98,156 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from "../../components/Auth/AuthContentWrapper";
|
||||
import SelectInput from "../../components/Others/Forms/SelectInput";
|
||||
import FormLabel from "../../components/Others/Forms/FormLabel";
|
||||
import InfoBox from "../../components/Others/Forms/InfoBox";
|
||||
import AuthContent from "../../components/Auth/AuthContent";
|
||||
import AuthButton from "../../components/Auth/AuthButton";
|
||||
import {SettingsIcon} from 'vue-feather-icons'
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import Headline from "../Auth/Headline"
|
||||
import {mapGetters} from 'vuex'
|
||||
import axios from 'axios'
|
||||
import {
|
||||
CheckIcon,
|
||||
XIcon,
|
||||
} from 'vue-feather-icons'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
|
||||
import SelectInput from '../../components/Others/Forms/SelectInput'
|
||||
import FormLabel from '../../components/Others/Forms/FormLabel'
|
||||
import InfoBox from '../../components/Others/Forms/InfoBox'
|
||||
import AuthContent from '../../components/Auth/AuthContent'
|
||||
import AuthButton from '../../components/Auth/AuthButton'
|
||||
import { SettingsIcon } from 'vue-feather-icons'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import Headline from '../Auth/Headline'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
import { CheckIcon, XIcon } from 'vue-feather-icons'
|
||||
|
||||
export default {
|
||||
name: 'StatusCheck',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SettingsIcon,
|
||||
SelectInput,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
CheckIcon,
|
||||
Headline,
|
||||
XIcon,
|
||||
},
|
||||
computed: {
|
||||
modules() {
|
||||
return this.$root.$data.config.statusCheck.modules
|
||||
},
|
||||
ini() {
|
||||
return this.$root.$data.config.statusCheck.ini
|
||||
},
|
||||
phpVersion() {
|
||||
return this.$root.$data.config.statusCheck.php_version
|
||||
},
|
||||
isCheckedAPI() {
|
||||
return typeof this.apiRunning !== 'undefined'
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
apiRunning: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
lastCheckBeforeNextPage() {
|
||||
let modulesCheck = Object
|
||||
.values(this.$root.$data.config.statusCheck.modules)
|
||||
.every(module => module === true)
|
||||
export default {
|
||||
name: 'StatusCheck',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SettingsIcon,
|
||||
SelectInput,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
CheckIcon,
|
||||
Headline,
|
||||
XIcon,
|
||||
},
|
||||
computed: {
|
||||
modules() {
|
||||
return this.$root.$data.config.statusCheck.modules
|
||||
},
|
||||
ini() {
|
||||
return this.$root.$data.config.statusCheck.ini
|
||||
},
|
||||
phpVersion() {
|
||||
return this.$root.$data.config.statusCheck.php_version
|
||||
},
|
||||
isCheckedAPI() {
|
||||
return typeof this.apiRunning !== 'undefined'
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
apiRunning: undefined,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
lastCheckBeforeNextPage() {
|
||||
let modulesCheck = Object.values(this.$root.$data.config.statusCheck.modules).every((module) => module === true)
|
||||
|
||||
let iniCheck = Object
|
||||
.values(this.$root.$data.config.statusCheck.ini)
|
||||
.every(setting => setting.status === true)
|
||||
let iniCheck = Object.values(this.$root.$data.config.statusCheck.ini).every((setting) => setting.status === true)
|
||||
|
||||
if (modulesCheck && iniCheck && this.apiRunning && this.phpVersion.acceptable) {
|
||||
this.$router.push({name: 'PurchaseCode'})
|
||||
} else {
|
||||
this.isError = true
|
||||
}
|
||||
},
|
||||
pingAPI() {
|
||||
axios.get('/api/setup/ping')
|
||||
.then(response => {
|
||||
if (response.data === 'pong') {
|
||||
this.apiRunning = true
|
||||
} else {
|
||||
this.apiRunning = false
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.apiRunning = false
|
||||
})
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
this.pingAPI()
|
||||
}
|
||||
}
|
||||
if (modulesCheck && iniCheck && this.apiRunning && this.phpVersion.acceptable) {
|
||||
this.$router.push({ name: 'PurchaseCode' })
|
||||
} else {
|
||||
this.isError = true
|
||||
}
|
||||
},
|
||||
pingAPI() {
|
||||
axios
|
||||
.get('/api/setup/ping')
|
||||
.then((response) => {
|
||||
if (response.data === 'pong') {
|
||||
this.apiRunning = true
|
||||
} else {
|
||||
this.apiRunning = false
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
this.apiRunning = false
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
this.pingAPI()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../../../sass/vuefilemanager/forms';
|
||||
@import '../../../sass/vuefilemanager/auth';
|
||||
@import '../../../sass/vuefilemanager/setup_wizard';
|
||||
@import '../../../sass/vuefilemanager/forms';
|
||||
@import '../../../sass/vuefilemanager/auth';
|
||||
@import '../../../sass/vuefilemanager/setup_wizard';
|
||||
|
||||
.check-list {
|
||||
display: block;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.12);
|
||||
padding: 5px 20px;
|
||||
margin-bottom: 50px;
|
||||
.check-list {
|
||||
display: block;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.12);
|
||||
padding: 5px 20px;
|
||||
margin-bottom: 50px;
|
||||
|
||||
.check-item {
|
||||
padding: 12px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid $light_mode_border;
|
||||
.check-item {
|
||||
padding: 12px 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
border-bottom: 1px solid $light_mode_border;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
}
|
||||
|
||||
.status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.note {
|
||||
margin-left: 10px;
|
||||
@include font-size(12);
|
||||
font-weight: 600;
|
||||
color: $text-muted;
|
||||
}
|
||||
.note {
|
||||
margin-left: 10px;
|
||||
@include font-size(12);
|
||||
font-weight: 600;
|
||||
color: $text-muted;
|
||||
}
|
||||
|
||||
&.success {
|
||||
.note {
|
||||
color: #00BC7E;
|
||||
}
|
||||
&.success {
|
||||
.note {
|
||||
color: #00bc7e;
|
||||
}
|
||||
|
||||
polyline {
|
||||
color: #00BC7E;
|
||||
}
|
||||
}
|
||||
polyline {
|
||||
color: #00bc7e;
|
||||
}
|
||||
}
|
||||
|
||||
&.danger {
|
||||
.note {
|
||||
color: #fd397a;
|
||||
}
|
||||
&.danger {
|
||||
.note {
|
||||
color: #fd397a;
|
||||
}
|
||||
|
||||
line {
|
||||
color: #fd397a;
|
||||
}
|
||||
}
|
||||
}
|
||||
line {
|
||||
color: #fd397a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.parameter {
|
||||
@include font-size(14);
|
||||
}
|
||||
.parameter {
|
||||
@include font-size(14);
|
||||
}
|
||||
|
||||
.help {
|
||||
@include font-size(12);
|
||||
color: $text-muted;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.help {
|
||||
@include font-size(12);
|
||||
color: $text-muted;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,20 +1,18 @@
|
||||
<template>
|
||||
<AuthContentWrapper ref="auth">
|
||||
|
||||
<!--Database Credentials-->
|
||||
<AuthContent name="database-credentials" :visible="true">
|
||||
|
||||
<Headline
|
||||
class="container mx-auto max-w-screen-sm"
|
||||
title="Setup Wizard"
|
||||
description="Set up your database credentials."
|
||||
>
|
||||
<Headline class="container mx-auto max-w-screen-sm" title="Setup Wizard" description="Set up your database credentials.">
|
||||
<settings-icon size="40" class="title-icon text-theme mx-auto" />
|
||||
</Headline>
|
||||
</Headline>
|
||||
|
||||
<ValidationObserver @submit.prevent="stripeCredentialsSubmit" ref="stripeCredentials" v-slot="{ invalid }" tag="form" class="form block-form">
|
||||
<InfoBox>
|
||||
<p>If you don’t have stripe account, please <a href="https://dashboard.stripe.com/register" target="_blank">register here</a> and get your Publishable Key, Secret Key and create your webhook.</p>
|
||||
<p>
|
||||
If you don’t have stripe account, please
|
||||
<a href="https://dashboard.stripe.com/register" target="_blank">register here</a>
|
||||
and get your Publishable Key, Secret Key and create your webhook.
|
||||
</p>
|
||||
</InfoBox>
|
||||
|
||||
<FormLabel>Stripe Setup</FormLabel>
|
||||
@@ -22,7 +20,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Stripe Currency:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Currency" rules="required" v-slot="{ errors }">
|
||||
<SelectInput v-model="stripeCredentials.currency" :options="currencyList" placeholder="Select your Stripe currency" :isError="errors[0]"/>
|
||||
<SelectInput v-model="stripeCredentials.currency" :options="currencyList" placeholder="Select your Stripe currency" :isError="errors[0]" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -32,7 +30,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Publishable Key:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Publishable Key" rules="required" v-slot="{ errors }">
|
||||
<input v-model="stripeCredentials.key" placeholder="Paste your publishable key" type="text" :class="{'border-red': errors[0]}"/>
|
||||
<input v-model="stripeCredentials.key" placeholder="Paste your publishable key" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -40,22 +38,24 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Secret Key:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Secret Key" rules="required" v-slot="{ errors }">
|
||||
<input v-model="stripeCredentials.secret" placeholder="Paste your secret key" type="text" :class="{'border-red': errors[0]}"/>
|
||||
<input v-model="stripeCredentials.secret" placeholder="Paste your secret key" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<FormLabel class="mt-70">Stripe Webhook</FormLabel>
|
||||
<InfoBox>
|
||||
<p>You have to create webhook endpoint in your Stripe Dashboard. You can find it in <b>Dashboard -> Developers -> Webhooks -> Add Endpoint</b>. In Endpoint URL
|
||||
please copy and paste url bellow. Make sure, this url is your public domain, not localhost. In events section, please click on <b>receive all events</b>.
|
||||
That's all.</p>
|
||||
<p>
|
||||
You have to create webhook endpoint in your Stripe Dashboard. You can find it in
|
||||
<b>Dashboard -> Developers -> Webhooks -> Add Endpoint</b>. In Endpoint URL please copy and paste url bellow. Make sure, this url is your public domain, not
|
||||
localhost. In events section, please click on <b>receive all events</b>. That's all.
|
||||
</p>
|
||||
</InfoBox>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Endpoint URL:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Webhook URL" rules="required" v-slot="{ errors }">
|
||||
<input :value="stripeWebhookEndpoint" type="text" disabled/>
|
||||
<input :value="stripeWebhookEndpoint" type="text" disabled />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -63,7 +63,7 @@
|
||||
<div class="block-wrapper">
|
||||
<label>Webhook Secret:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Webhook Secret" rules="required" v-slot="{ errors }">
|
||||
<input v-model="stripeCredentials.webhookSecret" placeholder="Type your stripe webhook secret" type="text" :class="{'border-red': errors[0]}"/>
|
||||
<input v-model="stripeCredentials.webhookSecret" placeholder="Type your stripe webhook secret" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
@@ -73,110 +73,106 @@
|
||||
</InfoBox>
|
||||
|
||||
<div class="submit-wrapper">
|
||||
<AuthButton icon="chevron-right" :text="submitButtonText" :loading="isLoading" :disabled="isLoading"/>
|
||||
<AuthButton icon="chevron-right" :text="submitButtonText" :loading="isLoading" :disabled="isLoading" />
|
||||
</div>
|
||||
|
||||
</ValidationObserver>
|
||||
</AuthContent>
|
||||
</AuthContentWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from "../../components/Auth/AuthContentWrapper";
|
||||
import SelectInput from "../../components/Others/Forms/SelectInput";
|
||||
import FormLabel from "../../components/Others/Forms/FormLabel";
|
||||
import InfoBox from "../../components/Others/Forms/InfoBox";
|
||||
import AuthContent from "../../components/Auth/AuthContent";
|
||||
import AuthButton from "../../components/Auth/AuthButton";
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {SettingsIcon} from 'vue-feather-icons'
|
||||
import Headline from "../Auth/Headline"
|
||||
import {mapGetters} from 'vuex'
|
||||
import axios from 'axios'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
|
||||
import SelectInput from '../../components/Others/Forms/SelectInput'
|
||||
import FormLabel from '../../components/Others/Forms/FormLabel'
|
||||
import InfoBox from '../../components/Others/Forms/InfoBox'
|
||||
import AuthContent from '../../components/Auth/AuthContent'
|
||||
import AuthButton from '../../components/Auth/AuthButton'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { SettingsIcon } from 'vue-feather-icons'
|
||||
import Headline from '../Auth/Headline'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'StripeCredentials',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SettingsIcon,
|
||||
SelectInput,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
Headline,
|
||||
export default {
|
||||
name: 'StripeCredentials',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SettingsIcon,
|
||||
SelectInput,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
Headline,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config', 'currencyList']),
|
||||
stripeWebhookEndpoint() {
|
||||
return this.config.host + '/stripe/webhook'
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config', 'currencyList']),
|
||||
stripeWebhookEndpoint() {
|
||||
return this.config.host + '/stripe/webhook'
|
||||
submitButtonText() {
|
||||
return this.isLoading ? 'Testing Stripe Connection' : 'Save and Set Billings'
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
errorMessage: '',
|
||||
stripeCredentials: {
|
||||
key: '',
|
||||
secret: '',
|
||||
webhookSecret: '',
|
||||
currency: '',
|
||||
},
|
||||
submitButtonText() {
|
||||
return this.isLoading ? 'Testing Stripe Connection' : 'Save and Set Billings'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
errorMessage: '',
|
||||
stripeCredentials: {
|
||||
key: '',
|
||||
secret: '',
|
||||
webhookSecret: '',
|
||||
currency: '',
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async stripeCredentialsSubmit() {
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.stripeCredentials.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup/stripe-credentials', this.stripeCredentials)
|
||||
.then(response => {
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
// Store Stripe Public
|
||||
this.$store.commit('SET_STRIPE_PUBLIC_KEY', this.stripeCredentials.key)
|
||||
|
||||
// Redirect to next step
|
||||
this.$router.push({name: 'BillingsDetail'})
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
if (error.response.status = 401) {
|
||||
this.isError = true
|
||||
this.errorMessage = error.response.data.message
|
||||
}
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async stripeCredentialsSubmit() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.stripeCredentials.validate()
|
||||
|
||||
if (!isValid) return
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup/stripe-credentials', this.stripeCredentials)
|
||||
.then((response) => {
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
|
||||
// Store Stripe Public
|
||||
this.$store.commit('SET_STRIPE_PUBLIC_KEY', this.stripeCredentials.key)
|
||||
|
||||
// Redirect to next step
|
||||
this.$router.push({ name: 'BillingsDetail' })
|
||||
})
|
||||
.catch((error) => {
|
||||
if ((error.response.status = 401)) {
|
||||
this.isError = true
|
||||
this.errorMessage = error.response.data.message
|
||||
}
|
||||
|
||||
// End loading
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../../../sass/vuefilemanager/forms';
|
||||
@import '../../../sass/vuefilemanager/auth';
|
||||
@import '../../../sass/vuefilemanager/setup_wizard';
|
||||
@import '../../../sass/vuefilemanager/forms';
|
||||
@import '../../../sass/vuefilemanager/auth';
|
||||
@import '../../../sass/vuefilemanager/setup_wizard';
|
||||
</style>
|
||||
|
||||
@@ -1,19 +1,12 @@
|
||||
<template>
|
||||
<AuthContentWrapper ref="auth">
|
||||
|
||||
<!--Database Credentials-->
|
||||
<AuthContent name="database-credentials" :visible="true">
|
||||
|
||||
<Headline
|
||||
class="container mx-auto max-w-screen-sm"
|
||||
title="Setup Wizard"
|
||||
description="Set up plans for your customers."
|
||||
>
|
||||
<Headline class="container mx-auto max-w-screen-sm" title="Setup Wizard" description="Set up plans for your customers.">
|
||||
<settings-icon size="40" class="title-icon text-theme mx-auto" />
|
||||
</Headline>
|
||||
</Headline>
|
||||
|
||||
<ValidationObserver @submit.prevent="subscriptionPlansSubmit" ref="subscriptionPlans" v-slot="{ invalid }"
|
||||
tag="form" class="form block-form">
|
||||
<ValidationObserver @submit.prevent="subscriptionPlansSubmit" ref="subscriptionPlans" v-slot="{ invalid }" tag="form" class="form block-form">
|
||||
<FormLabel>Create your plans</FormLabel>
|
||||
<InfoBox>
|
||||
<p>Your plans will be <b>sorted automatically</b> in ascent order by plan price. All plans is automatically created as monthly plans.</p>
|
||||
@@ -25,56 +18,53 @@
|
||||
<b class="duplicator-title">{{ index }}. Plan</b>
|
||||
<div class="block-wrapper">
|
||||
<label>Name:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Name"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<input v-model="plan.attributes.name" placeholder="Type your plan name"
|
||||
type="text" :class="{'border-red': errors[0]}"/>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Name" rules="required" v-slot="{ errors }">
|
||||
<input v-model="plan.attributes.name" placeholder="Type your plan name" type="text" :class="{ 'border-red': errors[0] }" />
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Description (optional):</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Description"
|
||||
v-slot="{ errors }">
|
||||
<textarea v-model="plan.attributes.description"
|
||||
placeholder="Type your plan description" :class="{'border-red': errors[0]}"></textarea>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Description" v-slot="{ errors }">
|
||||
<textarea v-model="plan.attributes.description" placeholder="Type your plan description" :class="{ 'border-red': errors[0] }"></textarea>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Price:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Price"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<input v-model="plan.attributes.price" placeholder="Type your plan price" type="number"
|
||||
step="0.01" min="1" max="999999999999"
|
||||
:class="{'border-red': errors[0]}"/>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Price" rules="required" v-slot="{ errors }">
|
||||
<input
|
||||
v-model="plan.attributes.price"
|
||||
placeholder="Type your plan price"
|
||||
type="number"
|
||||
step="0.01"
|
||||
min="1"
|
||||
max="999999999999"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
|
||||
<div class="block-wrapper">
|
||||
<label>Storage Capacity:</label>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Storage Capacity"
|
||||
rules="required" v-slot="{ errors }">
|
||||
<input v-model="plan.attributes.capacity"
|
||||
min="1"
|
||||
max="999999999"
|
||||
placeholder="Type storage capacity in GB"
|
||||
type="number"
|
||||
:class="{'border-red': errors[0]}"/>
|
||||
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Storage Capacity" rules="required" v-slot="{ errors }">
|
||||
<input
|
||||
v-model="plan.attributes.capacity"
|
||||
min="1"
|
||||
max="999999999"
|
||||
placeholder="Type storage capacity in GB"
|
||||
type="number"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ButtonBase
|
||||
@click.native="addRow"
|
||||
class="duplicator-add-button"
|
||||
button-style="theme-solid"
|
||||
>Add New Plan
|
||||
</ButtonBase>
|
||||
<ButtonBase @click.native="addRow" class="duplicator-add-button" button-style="theme-solid">Add New Plan </ButtonBase>
|
||||
</div>
|
||||
|
||||
<InfoBox v-if="isError" type="error" style="margin-top: 40px">
|
||||
@@ -82,8 +72,7 @@
|
||||
</InfoBox>
|
||||
|
||||
<div class="submit-wrapper">
|
||||
<AuthButton icon="chevron-right" :text="submitButtonText" :loading="isLoading"
|
||||
:disabled="isLoading"/>
|
||||
<AuthButton icon="chevron-right" :text="submitButtonText" :loading="isLoading" :disabled="isLoading" />
|
||||
</div>
|
||||
</ValidationObserver>
|
||||
</AuthContent>
|
||||
@@ -91,120 +80,116 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from "../../components/Auth/AuthContentWrapper";
|
||||
import SelectInput from "../../components/Others/Forms/SelectInput";
|
||||
import FormLabel from "../../components/Others/Forms/FormLabel";
|
||||
import ButtonBase from "../../components/FilesView/ButtonBase";
|
||||
import InfoBox from "../../components/Others/Forms/InfoBox";
|
||||
import AuthContent from "../../components/Auth/AuthContent";
|
||||
import AuthButton from "../../components/Auth/AuthButton";
|
||||
import {SettingsIcon} from 'vue-feather-icons'
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {XIcon} from 'vue-feather-icons'
|
||||
import Headline from "../Auth/Headline"
|
||||
import {mapGetters} from 'vuex'
|
||||
import axios from 'axios'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
|
||||
import SelectInput from '../../components/Others/Forms/SelectInput'
|
||||
import FormLabel from '../../components/Others/Forms/FormLabel'
|
||||
import ButtonBase from '../../components/FilesView/ButtonBase'
|
||||
import InfoBox from '../../components/Others/Forms/InfoBox'
|
||||
import AuthContent from '../../components/Auth/AuthContent'
|
||||
import AuthButton from '../../components/Auth/AuthButton'
|
||||
import { SettingsIcon } from 'vue-feather-icons'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { XIcon } from 'vue-feather-icons'
|
||||
import Headline from '../Auth/Headline'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'subscriptionPlans',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SettingsIcon,
|
||||
SelectInput,
|
||||
AuthContent,
|
||||
ButtonBase,
|
||||
AuthButton,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
XIcon,
|
||||
Headline,
|
||||
export default {
|
||||
name: 'subscriptionPlans',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
SettingsIcon,
|
||||
SelectInput,
|
||||
AuthContent,
|
||||
ButtonBase,
|
||||
AuthButton,
|
||||
FormLabel,
|
||||
required,
|
||||
InfoBox,
|
||||
XIcon,
|
||||
Headline,
|
||||
},
|
||||
computed: {
|
||||
submitButtonText() {
|
||||
return this.isLoading ? 'Creating Subscription Stripe Plans' : 'Save and Go Next'
|
||||
},
|
||||
computed: {
|
||||
submitButtonText() {
|
||||
return this.isLoading ? 'Creating Subscription Stripe Plans' : 'Save and Go Next'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
errorMessage: '',
|
||||
subscriptionPlans: [
|
||||
{
|
||||
id: 1,
|
||||
type: 'plan',
|
||||
attributes: {
|
||||
name: '',
|
||||
description: '',
|
||||
price: '',
|
||||
capacity: '',
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async subscriptionPlansSubmit() {
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.subscriptionPlans.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
this.isError = false
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup/stripe-plans', {
|
||||
plans: this.subscriptionPlans
|
||||
})
|
||||
.then(() => {
|
||||
|
||||
// Redirect to next step
|
||||
this.$router.push({name: 'EnvironmentSetup'})
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
if (error.response.status = 500) {
|
||||
this.isError = true
|
||||
this.errorMessage = error.response.data.message
|
||||
}
|
||||
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
addRow() {
|
||||
this.subscriptionPlans.push({
|
||||
id: Math.floor(Math.random() * 10000000),
|
||||
type: 'plans',
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
isError: false,
|
||||
errorMessage: '',
|
||||
subscriptionPlans: [
|
||||
{
|
||||
id: 1,
|
||||
type: 'plan',
|
||||
attributes: {
|
||||
name: '',
|
||||
description: '',
|
||||
price: '',
|
||||
capacity: '',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async subscriptionPlansSubmit() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.subscriptionPlans.validate()
|
||||
|
||||
if (!isValid) return
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
this.isError = false
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/setup/stripe-plans', {
|
||||
plans: this.subscriptionPlans,
|
||||
})
|
||||
.then(() => {
|
||||
// Redirect to next step
|
||||
this.$router.push({ name: 'EnvironmentSetup' })
|
||||
})
|
||||
.catch((error) => {
|
||||
if ((error.response.status = 500)) {
|
||||
this.isError = true
|
||||
this.errorMessage = error.response.data.message
|
||||
}
|
||||
})
|
||||
},
|
||||
removeRow(plan) {
|
||||
this.subscriptionPlans = this.subscriptionPlans.filter(item => item.id !== plan.id)
|
||||
},
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
}
|
||||
}
|
||||
addRow() {
|
||||
this.subscriptionPlans.push({
|
||||
id: Math.floor(Math.random() * 10000000),
|
||||
type: 'plans',
|
||||
attributes: {
|
||||
name: '',
|
||||
description: '',
|
||||
price: '',
|
||||
capacity: '',
|
||||
},
|
||||
})
|
||||
},
|
||||
removeRow(plan) {
|
||||
this.subscriptionPlans = this.subscriptionPlans.filter((item) => item.id !== plan.id)
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../../../sass/vuefilemanager/forms';
|
||||
@import '../../../sass/vuefilemanager/auth';
|
||||
@import '../../../sass/vuefilemanager/setup_wizard';
|
||||
@import '../../../sass/vuefilemanager/forms';
|
||||
@import '../../../sass/vuefilemanager/auth';
|
||||
@import '../../../sass/vuefilemanager/setup_wizard';
|
||||
</style>
|
||||
|
||||
@@ -1,27 +1,25 @@
|
||||
<template>
|
||||
<AuthContentWrapper ref="auth">
|
||||
|
||||
<!--Licence Verify-->
|
||||
<AuthContent name="subscription-service" :visible="true">
|
||||
|
||||
<Headline
|
||||
class="container mx-auto max-w-screen-sm"
|
||||
title="Setup Wizard"
|
||||
description="You can charge users for storage space by monthly billing plans. Please, select your charging service or skip this step if you don't want charge users:"
|
||||
>
|
||||
<Headline
|
||||
class="container mx-auto max-w-screen-sm"
|
||||
title="Setup Wizard"
|
||||
description="You can charge users for storage space by monthly billing plans. Please, select your charging service or skip this step if you don't want charge users:"
|
||||
>
|
||||
<settings-icon size="40" class="title-icon text-theme mx-auto" />
|
||||
</Headline>
|
||||
</Headline>
|
||||
|
||||
<div class="services">
|
||||
<router-link :to="{name: 'StripeCredentials'}" tag="div" class="service-card">
|
||||
<img src="/assets/icons/stripe-service.svg" alt="Stripe" class="service-logo">
|
||||
<router-link :to="{ name: 'StripeCredentials' }" tag="div" class="service-card">
|
||||
<img src="/assets/icons/stripe-service.svg" alt="Stripe" class="service-logo" />
|
||||
|
||||
<div class="service-content">
|
||||
<b class="service-title">Charging with Stripe</b>
|
||||
<p class="service-description">You can create custom storage plans and charge your users with monthly subscription.</p>
|
||||
</div>
|
||||
|
||||
<router-link :to="{name: 'StripeCredentials'}" class="service-link">
|
||||
<router-link :to="{ name: 'StripeCredentials' }" class="service-link">
|
||||
<span>Set Up Billing and Plans With Stripe</span>
|
||||
<chevron-right-icon size="22" class="icon"></chevron-right-icon>
|
||||
</router-link>
|
||||
@@ -29,8 +27,8 @@
|
||||
</div>
|
||||
|
||||
<p class="additional-link">
|
||||
<router-link :to="{name: 'EnvironmentSetup'}">
|
||||
<AuthButton class="skip-subscription-setup" icon="chevron-right" text="I will set up Stripe later" />
|
||||
<router-link :to="{ name: 'EnvironmentSetup' }">
|
||||
<AuthButton class="skip-subscription-setup" icon="chevron-right" text="I will set up Stripe later" />
|
||||
</router-link>
|
||||
</p>
|
||||
</AuthContent>
|
||||
@@ -38,114 +36,114 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AuthContentWrapper from "../../components/Auth/AuthContentWrapper";
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContent from "../../components/Auth/AuthContent";
|
||||
import AuthButton from "../../components/Auth/AuthButton";
|
||||
import { SettingsIcon, ChevronRightIcon } from 'vue-feather-icons'
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import Headline from "../Auth/Headline"
|
||||
import {mapGetters} from 'vuex'
|
||||
import axios from 'axios'
|
||||
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContent from '../../components/Auth/AuthContent'
|
||||
import AuthButton from '../../components/Auth/AuthButton'
|
||||
import { SettingsIcon, ChevronRightIcon } from 'vue-feather-icons'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import Headline from '../Auth/Headline'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'SubscriptionService',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
ChevronRightIcon,
|
||||
SettingsIcon,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
required,
|
||||
Headline,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
export default {
|
||||
name: 'SubscriptionService',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
ChevronRightIcon,
|
||||
SettingsIcon,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
required,
|
||||
Headline,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$scrollTop()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../../../sass/vuefilemanager/auth';
|
||||
@import '../../../sass/vuefilemanager/setup_wizard';
|
||||
@import '../../../sass/vuefilemanager/auth';
|
||||
@import '../../../sass/vuefilemanager/setup_wizard';
|
||||
|
||||
.services {
|
||||
margin: 0 auto;
|
||||
.services {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.service-card {
|
||||
text-align: left;
|
||||
box-shadow: 0 5px 30px 5px rgba(#3d4efd, 0.25);
|
||||
border-radius: 20px;
|
||||
max-width: 415px;
|
||||
display: inline-block;
|
||||
padding: 30px;
|
||||
background: rgb(58, 75, 255);
|
||||
background: linear-gradient(135deg, rgba(58, 75, 255, 1) 0%, rgba(103, 114, 229, 1) 100%);
|
||||
@include transition(200ms);
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
box-shadow: 0 8px 35px 5px rgba(#3d4efd, 0.4);
|
||||
@include transform(scale(1.02));
|
||||
}
|
||||
|
||||
.service-card {
|
||||
text-align: left;
|
||||
box-shadow: 0 5px 30px 5px rgba(#3D4EFD, 0.25);
|
||||
border-radius: 20px;
|
||||
max-width: 415px;
|
||||
display: inline-block;
|
||||
padding: 30px;
|
||||
background: rgb(58,75,255);
|
||||
background: linear-gradient(135deg, rgba(58,75,255,1) 0%, rgba(103,114,229,1) 100%);
|
||||
@include transition(200ms);
|
||||
.service-logo {
|
||||
margin-bottom: 30px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
box-shadow: 0 8px 35px 5px rgba(#3D4EFD, 0.4);
|
||||
@include transform(scale(1.02));
|
||||
}
|
||||
.service-content {
|
||||
margin-bottom: 65px;
|
||||
|
||||
.service-logo {
|
||||
margin-bottom: 30px;
|
||||
.service-title {
|
||||
@include font-size(18);
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
margin-bottom: 5px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.service-content {
|
||||
margin-bottom: 65px;
|
||||
|
||||
.service-title {
|
||||
@include font-size(18);
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
margin-bottom: 5px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.service-description {
|
||||
@include font-size(16);
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
.service-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.icon {
|
||||
margin-left: 5px;
|
||||
|
||||
polyline {
|
||||
stroke: white
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
@include font-size(16);
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
}
|
||||
.service-description {
|
||||
@include font-size(16);
|
||||
font-weight: 600;
|
||||
color: white;
|
||||
opacity: 0.8;
|
||||
}
|
||||
}
|
||||
|
||||
.skip-subscription-setup {
|
||||
border: none !important;
|
||||
}
|
||||
.service-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.auth-form input {
|
||||
min-width: 380px;
|
||||
.icon {
|
||||
margin-left: 5px;
|
||||
|
||||
polyline {
|
||||
stroke: white;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
@include font-size(16);
|
||||
font-weight: 700;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.skip-subscription-setup {
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.auth-form input {
|
||||
min-width: 380px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
<template>
|
||||
<div class="sm:flex md:h-screen md:overflow-hidden">
|
||||
|
||||
<!--Loading Spinner-->
|
||||
<Spinner v-if="isLoading" />
|
||||
|
||||
<!--File preview window-->
|
||||
<FilePreview />
|
||||
<Spotlight />
|
||||
<Spotlight />
|
||||
|
||||
<!--Popups-->
|
||||
<ProcessingPopup />
|
||||
@@ -24,125 +23,125 @@
|
||||
<DragUI />
|
||||
<Alert />
|
||||
|
||||
<NavigationSharePanel v-if="sharedDetail && $router.currentRoute.name === 'Public'"/>
|
||||
<NavigationSharePanel v-if="sharedDetail && $router.currentRoute.name === 'Public'" />
|
||||
|
||||
<div
|
||||
@contextmenu.prevent.capture="contextMenu($event, undefined)"
|
||||
class="md:grid md:content-start sm:flex-grow sm:px-3.5 transition-transform duration-300"
|
||||
:class="{'transform scale-97 origin-center': isScaledDown}"
|
||||
>
|
||||
<DesktopToolbar />
|
||||
<div
|
||||
@contextmenu.prevent.capture="contextMenu($event, undefined)"
|
||||
class="transition-transform duration-300 sm:flex-grow sm:px-3.5 md:grid md:content-start"
|
||||
:class="{ 'origin-center scale-97 transform': isScaledDown }"
|
||||
>
|
||||
<DesktopToolbar />
|
||||
|
||||
<MobileToolbar />
|
||||
<MobileToolbar />
|
||||
|
||||
<!--File list & info sidebar-->
|
||||
<div class="flex space-x-6 md:overflow-hidden md:h-full">
|
||||
<!--File list & info sidebar-->
|
||||
<div class="flex space-x-6 md:h-full md:overflow-hidden">
|
||||
<router-view
|
||||
id="file-view"
|
||||
:class="{
|
||||
'w-full md:w-4/6 2xl:w-5/6': isVisibleSidebar,
|
||||
'w-full': !isVisibleSidebar,
|
||||
}"
|
||||
class="relative"
|
||||
:key="$route.fullPath"
|
||||
/>
|
||||
|
||||
<router-view
|
||||
id="file-view"
|
||||
:class="{'2xl:w-5/6 md:w-4/6 w-full': isVisibleSidebar, 'w-full': ! isVisibleSidebar}"
|
||||
class="relative"
|
||||
:key="$route.fullPath"
|
||||
/>
|
||||
|
||||
<InfoSidebar
|
||||
v-if="isVisibleSidebar"
|
||||
class="2xl:w-72 w-2/6 overflow-y-auto overflow-x-hidden h-screen md:block hidden"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<InfoSidebar v-if="isVisibleSidebar" class="hidden h-screen w-2/6 overflow-y-auto overflow-x-hidden md:block 2xl:w-72" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MobileToolbar from "../components/FilesView/MobileToolbar";
|
||||
import InfoSidebar from "../components/FilesView/InfoSidebar";
|
||||
import MobileMultiSelectToolbar from "../components/FilesView/MobileMultiSelectToolbar";
|
||||
import FileSortingMobile from "../components/FilesView/FileSortingMobile";
|
||||
import CreateFolderPopup from "../components/Others/CreateFolderPopup";
|
||||
import ProcessingPopup from "../components/FilesView/ProcessingPopup";
|
||||
import NavigationSharePanel from "./FileView/Components/NavigationSharePanel"
|
||||
import RenameItemPopup from "../components/Others/RenameItemPopup";
|
||||
import FilePreview from "../components/FilePreview/FilePreview";
|
||||
import MoveItemPopup from "../components/Others/MoveItemPopup";
|
||||
import DesktopToolbar from "../components/FilesView/DesktopToolbar"
|
||||
import Spinner from "../components/FilesView/Spinner";
|
||||
import Vignette from "../components/Others/Vignette";
|
||||
import DragUI from "../components/FilesView/DragUI";
|
||||
import Alert from "../components/FilesView/Alert";
|
||||
import Spotlight from "../components/Spotlight/Spotlight"
|
||||
import {events} from '../bus'
|
||||
import {mapGetters} from 'vuex'
|
||||
import MobileToolbar from '../components/FilesView/MobileToolbar'
|
||||
import InfoSidebar from '../components/FilesView/InfoSidebar'
|
||||
import MobileMultiSelectToolbar from '../components/FilesView/MobileMultiSelectToolbar'
|
||||
import FileSortingMobile from '../components/FilesView/FileSortingMobile'
|
||||
import CreateFolderPopup from '../components/Others/CreateFolderPopup'
|
||||
import ProcessingPopup from '../components/FilesView/ProcessingPopup'
|
||||
import NavigationSharePanel from './FileView/Components/NavigationSharePanel'
|
||||
import RenameItemPopup from '../components/Others/RenameItemPopup'
|
||||
import FilePreview from '../components/FilePreview/FilePreview'
|
||||
import MoveItemPopup from '../components/Others/MoveItemPopup'
|
||||
import DesktopToolbar from '../components/FilesView/DesktopToolbar'
|
||||
import Spinner from '../components/FilesView/Spinner'
|
||||
import Vignette from '../components/Others/Vignette'
|
||||
import DragUI from '../components/FilesView/DragUI'
|
||||
import Alert from '../components/FilesView/Alert'
|
||||
import Spotlight from '../components/Spotlight/Spotlight'
|
||||
import { events } from '../bus'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Shared',
|
||||
components: {
|
||||
MobileToolbar,
|
||||
InfoSidebar,
|
||||
NavigationSharePanel,
|
||||
MobileMultiSelectToolbar,
|
||||
CreateFolderPopup,
|
||||
FileSortingMobile,
|
||||
ProcessingPopup,
|
||||
RenameItemPopup,
|
||||
DesktopToolbar,
|
||||
MoveItemPopup,
|
||||
FilePreview,
|
||||
Spotlight,
|
||||
Vignette,
|
||||
Spinner,
|
||||
DragUI,
|
||||
Alert,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'isVisibleSidebar',
|
||||
'sharedDetail',
|
||||
'config',
|
||||
])
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
isScaledDown: false
|
||||
export default {
|
||||
name: 'Shared',
|
||||
components: {
|
||||
MobileToolbar,
|
||||
InfoSidebar,
|
||||
NavigationSharePanel,
|
||||
MobileMultiSelectToolbar,
|
||||
CreateFolderPopup,
|
||||
FileSortingMobile,
|
||||
ProcessingPopup,
|
||||
RenameItemPopup,
|
||||
DesktopToolbar,
|
||||
MoveItemPopup,
|
||||
FilePreview,
|
||||
Spotlight,
|
||||
Vignette,
|
||||
Spinner,
|
||||
DragUI,
|
||||
Alert,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['isVisibleSidebar', 'sharedDetail', 'config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
isScaledDown: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
spotlightListener(e) {
|
||||
if (e.key === 'k' && e.metaKey) {
|
||||
events.$emit('spotlight:show')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
spotlightListener(e) {
|
||||
if (e.key === 'k' && e.metaKey) {
|
||||
events.$emit('spotlight:show');
|
||||
}
|
||||
},
|
||||
contextMenu(event, item) {
|
||||
events.$emit('context-menu:show', event, item)
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
events.$on('mobile-menu:show', () => this.isScaledDown = true)
|
||||
contextMenu(event, item) {
|
||||
events.$emit('context-menu:show', event, item)
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
events.$on('mobile-menu:show', () => (this.isScaledDown = true))
|
||||
|
||||
this.$store.dispatch('getShareDetail', this.$route.params.token)
|
||||
.then(response => {
|
||||
this.isLoading = false
|
||||
this.$store.dispatch('getShareDetail', this.$route.params.token).then((response) => {
|
||||
this.isLoading = false
|
||||
|
||||
let type = response.data.data.attributes.type
|
||||
let routeName = this.$router.currentRoute.name
|
||||
let isProtected = response.data.data.attributes.protected
|
||||
let type = response.data.data.attributes.type
|
||||
let routeName = this.$router.currentRoute.name
|
||||
let isProtected = response.data.data.attributes.protected
|
||||
|
||||
// Show public file browser
|
||||
if (type === 'folder' && !isProtected && routeName !== 'Public') {
|
||||
this.$router.replace({name: 'Public', params: {token: this.$route.params.token, id: response.data.data.attributes.item_id}})
|
||||
}
|
||||
|
||||
// Show public single file
|
||||
if (type !== 'folder' && !isProtected && routeName !== 'SharedSingleFile') {
|
||||
this.$router.push({name: 'SharedSingleFile'})
|
||||
}
|
||||
|
||||
// Show authentication page
|
||||
if (isProtected && routeName !== 'SharedAuthentication') {
|
||||
this.$router.push({name: 'SharedAuthentication'})
|
||||
}
|
||||
// Show public file browser
|
||||
if (type === 'folder' && !isProtected && routeName !== 'Public') {
|
||||
this.$router.replace({
|
||||
name: 'Public',
|
||||
params: {
|
||||
token: this.$route.params.token,
|
||||
id: response.data.data.attributes.item_id,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Show public single file
|
||||
if (type !== 'folder' && !isProtected && routeName !== 'SharedSingleFile') {
|
||||
this.$router.push({ name: 'SharedSingleFile' })
|
||||
}
|
||||
|
||||
// Show authentication page
|
||||
if (isProtected && routeName !== 'SharedAuthentication') {
|
||||
this.$router.push({ name: 'SharedAuthentication' })
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,90 +1,100 @@
|
||||
<template>
|
||||
<AuthContentWrapper>
|
||||
<AuthContent name="password" :visible="true">
|
||||
<Headline
|
||||
:title="$t('page_shared.title')"
|
||||
:description="$t('page_shared.subtitle')"
|
||||
/>
|
||||
<ValidationObserver @submit.prevent="authenticateProtected" ref="authenticateProtected" v-slot="{ invalid }" tag="form" class="md:flex items-start md:space-x-4 md:space-y-0 space-y-4 mb-12">
|
||||
<ValidationProvider tag="div" mode="passive" class="w-full text-left" name="Password" rules="required" v-slot="{ errors }">
|
||||
<input v-model="password" :placeholder="$t('page_shared.placeholder_pass')" type="password" class="font-bold px-5 py-3.5 dark:bg-2x-dark-foreground bg-light-background w-full rounded-lg focus-border-theme appearance-none border border-transparent" :class="{'border-red': errors[0]}" />
|
||||
<span class="text-red-600 text-xs text-left" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
<AuthButton class="md:w-min w-full justify-center" icon="chevron-right" :text="$t('page_shared.submit')" :loading="isLoading" :disabled="isLoading" />
|
||||
</ValidationObserver>
|
||||
</AuthContent>
|
||||
</AuthContentWrapper>
|
||||
<AuthContentWrapper>
|
||||
<AuthContent name="password" :visible="true">
|
||||
<Headline :title="$t('page_shared.title')" :description="$t('page_shared.subtitle')" />
|
||||
<ValidationObserver
|
||||
@submit.prevent="authenticateProtected"
|
||||
ref="authenticateProtected"
|
||||
v-slot="{ invalid }"
|
||||
tag="form"
|
||||
class="mb-12 items-start space-y-4 md:flex md:space-x-4 md:space-y-0"
|
||||
>
|
||||
<ValidationProvider tag="div" mode="passive" class="w-full text-left" name="Password" rules="required" v-slot="{ errors }">
|
||||
<input
|
||||
v-model="password"
|
||||
:placeholder="$t('page_shared.placeholder_pass')"
|
||||
type="password"
|
||||
class="focus-border-theme w-full appearance-none rounded-lg border border-transparent bg-light-background px-5 py-3.5 font-bold dark:bg-2x-dark-foreground"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
<span class="text-left text-xs text-red-600" v-if="errors[0]">{{ errors[0] }}</span>
|
||||
</ValidationProvider>
|
||||
<AuthButton class="w-full justify-center md:w-min" icon="chevron-right" :text="$t('page_shared.submit')" :loading="isLoading" :disabled="isLoading" />
|
||||
</ValidationObserver>
|
||||
</AuthContent>
|
||||
</AuthContentWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from "../../components/Auth/AuthContentWrapper"
|
||||
import AuthContent from "../../components/Auth/AuthContent";
|
||||
import AuthButton from "../../components/Auth/AuthButton";
|
||||
import Headline from "../Auth/Headline";
|
||||
import {mapGetters} from "vuex";
|
||||
import axios from "axios";
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
|
||||
import AuthContent from '../../components/Auth/AuthContent'
|
||||
import AuthButton from '../../components/Auth/AuthButton'
|
||||
import Headline from '../Auth/Headline'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'SharedAuthentication',
|
||||
components: {
|
||||
ValidationObserver,
|
||||
ValidationProvider,
|
||||
AuthContentWrapper,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
Headline,
|
||||
export default {
|
||||
name: 'SharedAuthentication',
|
||||
components: {
|
||||
ValidationObserver,
|
||||
ValidationProvider,
|
||||
AuthContentWrapper,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
Headline,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
password: '',
|
||||
isLoading: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async authenticateProtected() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.authenticateProtected.validate()
|
||||
|
||||
if (!isValid) return
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/browse/authenticate/' + this.$route.params.token, {
|
||||
password: this.password,
|
||||
})
|
||||
.then((response) => {
|
||||
// Show file browser
|
||||
if (response.data.data.attributes.type === 'folder' && this.$router.currentRoute.name !== 'Public') {
|
||||
this.$router.replace({
|
||||
name: 'Public',
|
||||
params: {
|
||||
token: this.$route.params.token,
|
||||
id: response.data.data.attributes.item_id,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Show single file
|
||||
if (response.data.data.attributes.type !== 'folder' && this.$router.currentRoute.name !== 'SharedSingleFile') {
|
||||
this.$router.push({ name: 'SharedSingleFile' })
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response.status === 401)
|
||||
this.$refs.authenticateProtected.setErrors({
|
||||
Password: [error.response.data],
|
||||
})
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config',
|
||||
]),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
password: '',
|
||||
isLoading: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async authenticateProtected() {
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.authenticateProtected.validate();
|
||||
|
||||
if (!isValid) return;
|
||||
|
||||
// Start loading
|
||||
this.isLoading = true
|
||||
|
||||
// Send request to get verify account
|
||||
axios
|
||||
.post('/api/browse/authenticate/' + this.$route.params.token, {
|
||||
password: this.password
|
||||
})
|
||||
.then(response => {
|
||||
|
||||
// Show file browser
|
||||
if (response.data.data.attributes.type === 'folder' && this.$router.currentRoute.name !== 'Public') {
|
||||
this.$router.replace({name: 'Public', params: {token: this.$route.params.token, id: response.data.data.attributes.item_id}})
|
||||
}
|
||||
|
||||
// Show single file
|
||||
if (response.data.data.attributes.type !== 'folder' && this.$router.currentRoute.name !== 'SharedSingleFile') {
|
||||
this.$router.push({name: 'SharedSingleFile'})
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
|
||||
if (error.response.status === 401)
|
||||
this.$refs.authenticateProtected.setErrors({
|
||||
'Password': [error.response.data]
|
||||
});
|
||||
})
|
||||
.finally(() => {
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
<template>
|
||||
<div class="h-screen flex justify-center items-center">
|
||||
<div class="flex h-screen items-center justify-center">
|
||||
<div>
|
||||
<ItemGrid
|
||||
v-if="sharedFile"
|
||||
:entry="sharedFile"
|
||||
:highlight="true"
|
||||
:mobile-handler="true"
|
||||
/>
|
||||
<ItemGrid v-if="sharedFile" :entry="sharedFile" :highlight="true" :mobile-handler="true" />
|
||||
|
||||
<ButtonBase @click.native="download" button-style="theme">
|
||||
{{ $t('page_shared.download_file') }}
|
||||
@@ -16,35 +11,32 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ButtonBase from "../../components/FilesView/ButtonBase";
|
||||
import ItemGrid from "../../components/FilesView/ItemGrid"
|
||||
import {mapGetters} from "vuex"
|
||||
import ButtonBase from '../../components/FilesView/ButtonBase'
|
||||
import ItemGrid from '../../components/FilesView/ItemGrid'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'SharedSingleItem',
|
||||
components: {
|
||||
ButtonBase,
|
||||
ItemGrid,
|
||||
export default {
|
||||
name: 'SharedSingleItem',
|
||||
components: {
|
||||
ButtonBase,
|
||||
ItemGrid,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['sharedDetail', 'sharedFile']),
|
||||
},
|
||||
methods: {
|
||||
download() {
|
||||
this.$downloadFile(this.sharedFile.data.attributes.file_url, this.sharedFile.data.attributes.name + '.' + this.sharedFile.data.attributes.mimetype)
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'sharedDetail',
|
||||
'sharedFile',
|
||||
]),
|
||||
},
|
||||
methods: {
|
||||
download() {
|
||||
this.$downloadFile(this.sharedFile.data.attributes.file_url, this.sharedFile.data.attributes.name + '.' + this.sharedFile.data.attributes.mimetype)
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
if (!this.sharedDetail) {
|
||||
this.$store.dispatch('getShareDetail', this.$route.params.token).then(() => {
|
||||
this.$store.dispatch('getSingleFile')
|
||||
})
|
||||
} else {
|
||||
},
|
||||
mounted() {
|
||||
if (!this.sharedDetail) {
|
||||
this.$store.dispatch('getShareDetail', this.$route.params.token).then(() => {
|
||||
this.$store.dispatch('getSingleFile')
|
||||
}
|
||||
})
|
||||
} else {
|
||||
this.$store.dispatch('getSingleFile')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,173 +1,167 @@
|
||||
<template>
|
||||
<AuthContentWrapper ref="auth">
|
||||
|
||||
<!--Invitation info-->
|
||||
<AuthContent name="invitation" :visible="false">
|
||||
<Headline
|
||||
v-if="invitation"
|
||||
:title="$t('Invitation To Join Team Folder')"
|
||||
:description="$t('{name} invite you to join with his team into shared team folder', {name: invitation.data.relationships.inviter.data.attributes.name})"
|
||||
>
|
||||
<div class="text-center mb-10 w-24 mx-auto relative">
|
||||
<VueFolderTeamIcon class="inline-block w-28" />
|
||||
<MemberAvatar
|
||||
:member="invitation.data.relationships.inviter"
|
||||
class="absolute -bottom-2.5 -right-6"
|
||||
:is-border="true"
|
||||
:size="38"
|
||||
/>
|
||||
</div>
|
||||
</Headline>
|
||||
v-if="invitation"
|
||||
:title="$t('Invitation To Join Team Folder')"
|
||||
:description="
|
||||
$t('{name} invite you to join with his team into shared team folder', {
|
||||
name: invitation.data.relationships.inviter.data.attributes.name,
|
||||
})
|
||||
"
|
||||
>
|
||||
<div class="relative mx-auto mb-10 w-24 text-center">
|
||||
<VueFolderTeamIcon class="inline-block w-28" />
|
||||
<MemberAvatar :member="invitation.data.relationships.inviter" class="absolute -bottom-2.5 -right-6" :is-border="true" :size="38" />
|
||||
</div>
|
||||
</Headline>
|
||||
|
||||
<AuthButton
|
||||
@click.native="acceptInvitation"
|
||||
class="md:w-min w-full justify-center mb-12"
|
||||
icon="chevron-right"
|
||||
:text="$t('Accept Invitation')"
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
/>
|
||||
<AuthButton
|
||||
@click.native="acceptInvitation"
|
||||
class="mb-12 w-full justify-center md:w-min"
|
||||
icon="chevron-right"
|
||||
:text="$t('Accept Invitation')"
|
||||
:loading="isLoading"
|
||||
:disabled="isLoading"
|
||||
/>
|
||||
|
||||
<div class="block">
|
||||
Or
|
||||
<b @click="declineInvitation" class="text-theme font-bold cursor-pointer">
|
||||
Or
|
||||
<b @click="declineInvitation" class="text-theme cursor-pointer font-bold">
|
||||
{{ $t('decline') }}
|
||||
</b>
|
||||
your invitation.
|
||||
your invitation.
|
||||
</div>
|
||||
</AuthContent>
|
||||
|
||||
<!--Accepted invitation screen-->
|
||||
<AuthContent v-if="invitation" name="accepted" :visible="false">
|
||||
<Headline
|
||||
:title="$t('You are successfully joined')"
|
||||
:description="$t('You can now proceed to your account and participate in team folder')"
|
||||
/>
|
||||
<Headline :title="$t('You are successfully joined')" :description="$t('You can now proceed to your account and participate in team folder')" />
|
||||
|
||||
<router-link replace v-if="! config.isAuthenticated" :to="{name: 'SignIn'}">
|
||||
<AuthButton class="md:w-min w-full justify-center mb-12" icon="chevron-right" :text="$t('Proceed to your account')"/>
|
||||
<router-link replace v-if="!config.isAuthenticated" :to="{ name: 'SignIn' }">
|
||||
<AuthButton class="mb-12 w-full justify-center md:w-min" icon="chevron-right" :text="$t('Proceed to your account')" />
|
||||
</router-link>
|
||||
|
||||
<router-link replace v-if="config.isAuthenticated" :to="{name: 'SharedWithMe', params: {id: invitation.data.attributes.parent_id}}">
|
||||
<AuthButton class="md:w-min w-full justify-center mb-12" icon="chevron-right" :text="$t('Go to Team Folder')"/>
|
||||
<router-link
|
||||
replace
|
||||
v-if="config.isAuthenticated"
|
||||
:to="{
|
||||
name: 'SharedWithMe',
|
||||
params: { id: invitation.data.attributes.parent_id },
|
||||
}"
|
||||
>
|
||||
<AuthButton class="mb-12 w-full justify-center md:w-min" icon="chevron-right" :text="$t('Go to Team Folder')" />
|
||||
</router-link>
|
||||
</AuthContent>
|
||||
|
||||
<!--Denied invitation screen-->
|
||||
<AuthContent name="denied" :visible="false">
|
||||
<Headline :title="$t('You are successfully denied invitation')" :description="$t('You can now proceed to your account')" />
|
||||
|
||||
<Headline
|
||||
:title="$t('You are successfully denied invitation')"
|
||||
:description="$t('You can now proceed to your account')"
|
||||
/>
|
||||
|
||||
<router-link :to="{name: 'SignIn'}">
|
||||
<AuthButton class="md:w-min w-full justify-center mb-12" icon="chevron-right" :text="$t('Proceed to your account')"/>
|
||||
<router-link :to="{ name: 'SignIn' }">
|
||||
<AuthButton class="mb-12 w-full justify-center md:w-min" icon="chevron-right" :text="$t('Proceed to your account')" />
|
||||
</router-link>
|
||||
</AuthContent>
|
||||
|
||||
<!--Used or Expired invitation screen-->
|
||||
<AuthContent name="expired" :visible="false">
|
||||
<Headline :title="$t('Your invitation has been used')" :description="$t('We are sorry but this invitation was used previously')" />
|
||||
|
||||
<Headline
|
||||
:title="$t('Your invitation has been used')"
|
||||
:description="$t('We are sorry but this invitation was used previously')"
|
||||
/>
|
||||
|
||||
<router-link replace v-if="! config.isAuthenticated" :to="{name: 'SignIn'}">
|
||||
<AuthButton class="md:w-min w-full justify-center mb-12" icon="chevron-right" :text="$t('Log In')"/>
|
||||
<router-link replace v-if="!config.isAuthenticated" :to="{ name: 'SignIn' }">
|
||||
<AuthButton class="mb-12 w-full justify-center md:w-min" icon="chevron-right" :text="$t('Log In')" />
|
||||
</router-link>
|
||||
|
||||
<router-link replace v-if="config.isAuthenticated" :to="{name: 'SharedWithMe'}">
|
||||
<AuthButton class="md:w-min w-full justify-center mb-12" icon="chevron-right" :text="$t('Go to your shared folders')"/>
|
||||
<router-link replace v-if="config.isAuthenticated" :to="{ name: 'SharedWithMe' }">
|
||||
<AuthButton class="mb-12 w-full justify-center md:w-min" icon="chevron-right" :text="$t('Go to your shared folders')" />
|
||||
</router-link>
|
||||
</AuthContent>
|
||||
</AuthContentWrapper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {ValidationObserver, ValidationProvider} from 'vee-validate/dist/vee-validate.full'
|
||||
import VueFolderTeamIcon from "../../components/FilesView/Icons/VueFolderTeamIcon"
|
||||
import AuthContentWrapper from "../../components/Auth/AuthContentWrapper";
|
||||
import AuthContent from "../../components/Auth/AuthContent";
|
||||
import MemberAvatar from "../../components/FilesView/MemberAvatar"
|
||||
import AuthButton from "../../components/Auth/AuthButton";
|
||||
import Spinner from "../../components/FilesView/Spinner";
|
||||
import Headline from "../Auth/Headline"
|
||||
import {mapGetters} from 'vuex'
|
||||
import axios from 'axios'
|
||||
import { ValidationObserver, ValidationProvider } from 'vee-validate/dist/vee-validate.full'
|
||||
import VueFolderTeamIcon from '../../components/FilesView/Icons/VueFolderTeamIcon'
|
||||
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
|
||||
import AuthContent from '../../components/Auth/AuthContent'
|
||||
import MemberAvatar from '../../components/FilesView/MemberAvatar'
|
||||
import AuthButton from '../../components/Auth/AuthButton'
|
||||
import Spinner from '../../components/FilesView/Spinner'
|
||||
import Headline from '../Auth/Headline'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'Invitation',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
VueFolderTeamIcon,
|
||||
MemberAvatar,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
Headline,
|
||||
Spinner,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config'
|
||||
]),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
invitation: undefined,
|
||||
isUsed: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
acceptInvitation() {
|
||||
this.isLoading = true
|
||||
|
||||
axios.put(`/api/teams/invitations/${this.$router.currentRoute.params.id}`)
|
||||
.then(() => {
|
||||
this.goToAuthPage('accepted')
|
||||
})
|
||||
.catch(() => {
|
||||
this.$isSomethingWrong()
|
||||
})
|
||||
.finally(() => this.isLoading = false)
|
||||
},
|
||||
declineInvitation() {
|
||||
this.isLoading = true
|
||||
|
||||
axios.delete(`/api/teams/invitations/${this.$router.currentRoute.params.id}`)
|
||||
.then(() => {
|
||||
this.goToAuthPage('denied')
|
||||
})
|
||||
.catch(() => {
|
||||
this.$isSomethingWrong()
|
||||
})
|
||||
.finally(() => this.isLoading = false)
|
||||
},
|
||||
goToAuthPage(slug) {
|
||||
this.$refs.auth.$children.forEach(page => {
|
||||
|
||||
// Hide current step
|
||||
page.isVisible = page.$props.name === slug;
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
axios.get(`/api/teams/invitations/${this.$router.currentRoute.params.id}`)
|
||||
.then(response => {
|
||||
this.invitation = response.data
|
||||
this.goToAuthPage('invitation')
|
||||
})
|
||||
.catch(error => {
|
||||
if (error.response.status === 410) {
|
||||
this.goToAuthPage('expired')
|
||||
} else {
|
||||
this.$isSomethingWrong()
|
||||
}
|
||||
})
|
||||
export default {
|
||||
name: 'Invitation',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
VueFolderTeamIcon,
|
||||
MemberAvatar,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
Headline,
|
||||
Spinner,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
invitation: undefined,
|
||||
isUsed: false,
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
acceptInvitation() {
|
||||
this.isLoading = true
|
||||
|
||||
axios
|
||||
.put(`/api/teams/invitations/${this.$router.currentRoute.params.id}`)
|
||||
.then(() => {
|
||||
this.goToAuthPage('accepted')
|
||||
})
|
||||
.catch(() => {
|
||||
this.$isSomethingWrong()
|
||||
})
|
||||
.finally(() => (this.isLoading = false))
|
||||
},
|
||||
declineInvitation() {
|
||||
this.isLoading = true
|
||||
|
||||
axios
|
||||
.delete(`/api/teams/invitations/${this.$router.currentRoute.params.id}`)
|
||||
.then(() => {
|
||||
this.goToAuthPage('denied')
|
||||
})
|
||||
.catch(() => {
|
||||
this.$isSomethingWrong()
|
||||
})
|
||||
.finally(() => (this.isLoading = false))
|
||||
},
|
||||
goToAuthPage(slug) {
|
||||
this.$refs.auth.$children.forEach((page) => {
|
||||
// Hide current step
|
||||
page.isVisible = page.$props.name === slug
|
||||
})
|
||||
},
|
||||
},
|
||||
created() {
|
||||
axios
|
||||
.get(`/api/teams/invitations/${this.$router.currentRoute.params.id}`)
|
||||
.then((response) => {
|
||||
this.invitation = response.data
|
||||
this.goToAuthPage('invitation')
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response.status === 410) {
|
||||
this.goToAuthPage('expired')
|
||||
} else {
|
||||
this.$isSomethingWrong()
|
||||
}
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
<template>
|
||||
<AuthContentWrapper ref="auth">
|
||||
|
||||
<AuthContent :visible="true">
|
||||
<Headline
|
||||
:title="$t('Temporary Unavailable')"
|
||||
:description="$t('Unfortunately, this shared link is temporary unavailable. Please try it later.')"
|
||||
/>
|
||||
<Headline :title="$t('Temporary Unavailable')" :description="$t('Unfortunately, this shared link is temporary unavailable. Please try it later.')" />
|
||||
|
||||
<span class="additional-link">{{ $t('page_registration.have_an_account') }}
|
||||
<router-link :to="{name: 'SignIn'}">
|
||||
<span class="additional-link"
|
||||
>{{ $t('page_registration.have_an_account') }}
|
||||
<router-link :to="{ name: 'SignIn' }">
|
||||
{{ $t('page_forgotten_password.password_remember_button') }}
|
||||
</router-link>
|
||||
</span>
|
||||
@@ -17,22 +14,22 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AuthContentWrapper from "../components/Auth/AuthContentWrapper";
|
||||
import AuthContent from "../components/Auth/AuthContent";
|
||||
import AuthButton from "../components/Auth/AuthButton";
|
||||
import Headline from "./Auth/Headline"
|
||||
import AuthContentWrapper from '../components/Auth/AuthContentWrapper'
|
||||
import AuthContent from '../components/Auth/AuthContent'
|
||||
import AuthButton from '../components/Auth/AuthButton'
|
||||
import Headline from './Auth/Headline'
|
||||
|
||||
export default {
|
||||
name: 'NotFound',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
Headline,
|
||||
},
|
||||
}
|
||||
export default {
|
||||
name: 'NotFound',
|
||||
components: {
|
||||
AuthContentWrapper,
|
||||
AuthContent,
|
||||
AuthButton,
|
||||
Headline,
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../../sass/vuefilemanager/auth';
|
||||
@import '../../sass/vuefilemanager/auth';
|
||||
</style>
|
||||
|
||||
@@ -1,26 +1,26 @@
|
||||
<template>
|
||||
<PageTab>
|
||||
<!-- Metered subscription components -->
|
||||
<div v-if="config.subscriptionType === 'metered'">
|
||||
<!--Failed Payments-->
|
||||
<UserFailedPayments />
|
||||
<!-- Metered subscription components -->
|
||||
<div v-if="config.subscriptionType === 'metered'">
|
||||
<!--Failed Payments-->
|
||||
<UserFailedPayments />
|
||||
|
||||
<!--
|
||||
<!--
|
||||
...
|
||||
Charge user and increase his balance
|
||||
...
|
||||
Available for PayPal, Paystack
|
||||
...
|
||||
-->
|
||||
<UserBalance/>
|
||||
<UserBalance />
|
||||
|
||||
<!--Usage Estimates-->
|
||||
<UserUsageEstimates />
|
||||
<!--Usage Estimates-->
|
||||
<UserUsageEstimates />
|
||||
|
||||
<!--Billing Alert-->
|
||||
<UserBillingAlerts />
|
||||
<!--Billing Alert-->
|
||||
<UserBillingAlerts />
|
||||
|
||||
<!--
|
||||
<!--
|
||||
...
|
||||
We can store user credit card and charge for fixed billing and metered billing
|
||||
This component handle storing and showing payment card UI
|
||||
@@ -28,21 +28,21 @@
|
||||
Handle only Stripe
|
||||
...
|
||||
-->
|
||||
<UserStoredPaymentMethods />
|
||||
<UserStoredPaymentMethods />
|
||||
|
||||
<!-- Show all users transactions -->
|
||||
<UserTransactionsForMeteredBilling />
|
||||
</div>
|
||||
<!-- Show all users transactions -->
|
||||
<UserTransactionsForMeteredBilling />
|
||||
</div>
|
||||
|
||||
<!-- Fixed subscription components -->
|
||||
<div v-if="config.subscriptionType === 'fixed'">
|
||||
<!-- Empty subscription -->
|
||||
<UserEmptySubscription />
|
||||
<!-- Fixed subscription components -->
|
||||
<div v-if="config.subscriptionType === 'fixed'">
|
||||
<!-- Empty subscription -->
|
||||
<UserEmptySubscription />
|
||||
|
||||
<!-- Subscription Detail -->
|
||||
<UserFixedSubscriptionDetail />
|
||||
<!-- Subscription Detail -->
|
||||
<UserFixedSubscriptionDetail />
|
||||
|
||||
<!--
|
||||
<!--
|
||||
...
|
||||
We can store user credit card and charge for fixed billing and metered billing
|
||||
This component handle storing and showing payment card UI
|
||||
@@ -50,9 +50,9 @@
|
||||
Handle only Stripe
|
||||
...
|
||||
-->
|
||||
<UserStoredPaymentMethods />
|
||||
<UserStoredPaymentMethods />
|
||||
|
||||
<!--
|
||||
<!--
|
||||
...
|
||||
Paystack or PayPal need generate external resources to update payment method.
|
||||
This component will handle all user cases
|
||||
@@ -60,53 +60,50 @@
|
||||
Handle only Paypal, Paystack
|
||||
...
|
||||
-->
|
||||
<UserUpdatePaymentMethodsExternally />
|
||||
<UserUpdatePaymentMethodsExternally />
|
||||
|
||||
<!-- Component for cancel or upgrade subscription plan -->
|
||||
<UserEditSubscription />
|
||||
|
||||
<!-- Show all users transactions -->
|
||||
<UserTransactionsForFixedBilling />
|
||||
</div>
|
||||
<!-- Component for cancel or upgrade subscription plan -->
|
||||
<UserEditSubscription />
|
||||
|
||||
<!-- Show all users transactions -->
|
||||
<UserTransactionsForFixedBilling />
|
||||
</div>
|
||||
</PageTab>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import UserUpdatePaymentMethodsExternally from "../../components/Subscription/UserUpdatePaymentMethodsExternally"
|
||||
import UserTransactionsForMeteredBilling from "../../components/Subscription/UserTransactionsForMeteredBilling"
|
||||
import UserTransactionsForFixedBilling from "../../components/Subscription/UserTransactionsForFixedBilling"
|
||||
import UserFixedSubscriptionDetail from "../../components/Subscription/UserFixedSubscriptionDetail"
|
||||
import UserStoredPaymentMethods from "../../components/Subscription/UserStoredPaymentMethods"
|
||||
import UserEmptySubscription from "../../components/Subscription/UserEmptySubscription"
|
||||
import UserEditSubscription from "../../components/Subscription/UserEditSubscription"
|
||||
import UserFailedPayments from "../../components/Subscription/UserFailedPayments"
|
||||
import UserUsageEstimates from "../../components/Subscription/UserUsageEstimates"
|
||||
import UserBillingAlerts from "../../components/Subscription/UserBillingAlerts"
|
||||
import PageTab from "../../components/Others/Layout/PageTab";
|
||||
import UserBalance from "../../components/Subscription/UserBalance"
|
||||
import {mapGetters} from 'vuex'
|
||||
import UserUpdatePaymentMethodsExternally from '../../components/Subscription/UserUpdatePaymentMethodsExternally'
|
||||
import UserTransactionsForMeteredBilling from '../../components/Subscription/UserTransactionsForMeteredBilling'
|
||||
import UserTransactionsForFixedBilling from '../../components/Subscription/UserTransactionsForFixedBilling'
|
||||
import UserFixedSubscriptionDetail from '../../components/Subscription/UserFixedSubscriptionDetail'
|
||||
import UserStoredPaymentMethods from '../../components/Subscription/UserStoredPaymentMethods'
|
||||
import UserEmptySubscription from '../../components/Subscription/UserEmptySubscription'
|
||||
import UserEditSubscription from '../../components/Subscription/UserEditSubscription'
|
||||
import UserFailedPayments from '../../components/Subscription/UserFailedPayments'
|
||||
import UserUsageEstimates from '../../components/Subscription/UserUsageEstimates'
|
||||
import UserBillingAlerts from '../../components/Subscription/UserBillingAlerts'
|
||||
import PageTab from '../../components/Others/Layout/PageTab'
|
||||
import UserBalance from '../../components/Subscription/UserBalance'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Billing',
|
||||
components: {
|
||||
UserUpdatePaymentMethodsExternally,
|
||||
UserTransactionsForMeteredBilling,
|
||||
UserTransactionsForFixedBilling,
|
||||
UserFixedSubscriptionDetail,
|
||||
UserStoredPaymentMethods,
|
||||
UserEmptySubscription,
|
||||
UserEditSubscription,
|
||||
UserFailedPayments,
|
||||
UserUsageEstimates,
|
||||
UserBillingAlerts,
|
||||
UserBalance,
|
||||
PageTab,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config',
|
||||
]),
|
||||
},
|
||||
}
|
||||
export default {
|
||||
name: 'Billing',
|
||||
components: {
|
||||
UserUpdatePaymentMethodsExternally,
|
||||
UserTransactionsForMeteredBilling,
|
||||
UserTransactionsForFixedBilling,
|
||||
UserFixedSubscriptionDetail,
|
||||
UserStoredPaymentMethods,
|
||||
UserEmptySubscription,
|
||||
UserEditSubscription,
|
||||
UserFailedPayments,
|
||||
UserUsageEstimates,
|
||||
UserBillingAlerts,
|
||||
UserBalance,
|
||||
PageTab,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,291 +1,317 @@
|
||||
<template>
|
||||
<div v-if="user">
|
||||
|
||||
<!--2fa authentication-->
|
||||
<div v-if="! user.data.attributes.socialite_account" class="card shadow-card">
|
||||
<!--2fa authentication-->
|
||||
<div v-if="!user.data.attributes.socialite_account" class="card shadow-card">
|
||||
<FormLabel icon="smartphone">
|
||||
{{ $t('2fa.settings.title') }}
|
||||
</FormLabel>
|
||||
<AppInputSwitch :title="$t('popup_2fa.switch_title')" :description="$t('popup_2fa.switch_info')" :is-last="! user.data.attributes.two_factor_authentication">
|
||||
<AppInputSwitch :title="$t('popup_2fa.switch_title')" :description="$t('popup_2fa.switch_info')" :is-last="!user.data.attributes.two_factor_authentication">
|
||||
<SwitchInput v-model="user.data.attributes.two_factor_authentication" class="switch" :state="user.data.attributes.two_factor_authentication" />
|
||||
</AppInputSwitch>
|
||||
<AppInputButton v-if="user && user.data.attributes.two_factor_authentication" :title="$t('popup_2fa.codes_title')" :description="$t('popup_2fa.codes_info')" :is-last="true">
|
||||
<AppInputButton
|
||||
v-if="user && user.data.attributes.two_factor_authentication"
|
||||
:title="$t('popup_2fa.codes_title')"
|
||||
:description="$t('popup_2fa.codes_info')"
|
||||
:is-last="true"
|
||||
>
|
||||
<ButtonBase class="w-full" button-style="secondary" @click.native="showRecoveryCodes">
|
||||
{{ $t('popup_2fa.codes_button') }}
|
||||
</ButtonBase>
|
||||
</AppInputButton>
|
||||
</div>
|
||||
|
||||
<!--Get personal api keys-->
|
||||
<!--Get personal api keys-->
|
||||
<div class="card shadow-card">
|
||||
<FormLabel icon="key">
|
||||
{{ $t('personal_token.section_title') }}
|
||||
</FormLabel>
|
||||
<InfoBox v-if="tokens.length === 0">
|
||||
<p>{{ $t("personal_token.section_description") }}</p>
|
||||
<p>{{ $t('personal_token.section_description') }}</p>
|
||||
</InfoBox>
|
||||
|
||||
<div class="mb-5">
|
||||
<div v-if="tokens.length > 0" class="flex items-center justify-between py-2 border-b dark:border-opacity-5 border-light border-dashed" v-for="token in tokens" :key="token.id">
|
||||
<div class="leading-none">
|
||||
<b class="text-sm font-bold leading-none">
|
||||
{{ token.name }}
|
||||
</b>
|
||||
<time class="text-xs text-gray-500 pt-2 leading-none block">
|
||||
{{ $t('last_used') }}: {{ token.last_used_at ? formatDate(token.last_used_at) : $t('never') }}
|
||||
</time>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div @click="confirmDeleteToken(token)" class="cursor-pointer flex items-center justify-center w-8 h-8 rounded-md hover:bg-red-100 dark:bg-2x-dark-foreground bg-light-background transition-colors">
|
||||
<Trash2Icon size="15" class="opacity-75" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-5">
|
||||
<div
|
||||
v-if="tokens.length > 0"
|
||||
class="flex items-center justify-between border-b border-dashed border-light py-2 dark:border-opacity-5"
|
||||
v-for="token in tokens"
|
||||
:key="token.id"
|
||||
>
|
||||
<div class="leading-none">
|
||||
<b class="text-sm font-bold leading-none">
|
||||
{{ token.name }}
|
||||
</b>
|
||||
<time class="block pt-2 text-xs leading-none text-gray-500">
|
||||
{{ $t('last_used') }}:
|
||||
{{ token.last_used_at ? formatDate(token.last_used_at) : $t('never') }}
|
||||
</time>
|
||||
</div>
|
||||
<div class="text-right">
|
||||
<div
|
||||
@click="confirmDeleteToken(token)"
|
||||
class="flex h-8 w-8 cursor-pointer items-center justify-center rounded-md bg-light-background transition-colors hover:bg-red-100 dark:bg-2x-dark-foreground"
|
||||
>
|
||||
<Trash2Icon size="15" class="opacity-75" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ButtonBase @click.native="openCreateTokenPopup" type="submit" button-style="theme" class="sm:w-auto w-full">
|
||||
<ButtonBase @click.native="openCreateTokenPopup" type="submit" button-style="theme" class="w-full sm:w-auto">
|
||||
{{ $t('personal_token.create_token') }}
|
||||
</ButtonBase>
|
||||
</div>
|
||||
|
||||
<!--Change password-->
|
||||
<ValidationObserver ref="password" @submit.prevent="resetPassword" v-slot="{ invalid }" tag="form" class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('user_password.title') }}
|
||||
</FormLabel>
|
||||
<!--Change password-->
|
||||
<ValidationObserver ref="password" @submit.prevent="resetPassword" v-slot="{ invalid }" tag="form" class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('user_password.title') }}
|
||||
</FormLabel>
|
||||
|
||||
<ValidationProvider tag="div" mode="passive" name="Current Password" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Current Password')" :error="errors[0]">
|
||||
<input v-model="passwordForm.current" :placeholder="$t('Current password')" type="password" class="focus-border-theme input-dark" :class="{'border-red': errors[0]}" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="Current Password" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('Current Password')" :error="errors[0]">
|
||||
<input
|
||||
v-model="passwordForm.current"
|
||||
:placeholder="$t('Current password')"
|
||||
type="password"
|
||||
class="focus-border-theme input-dark"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<ValidationProvider tag="div" mode="passive" name="New Password" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('page_create_password.label_new_pass')" :error="errors[0]">
|
||||
<input v-model="passwordForm.password" :placeholder="$t('page_create_password.label_new_pass')" type="password" class="focus-border-theme input-dark" :class="{'border-red': errors[0]}" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="New Password" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('page_create_password.label_new_pass')" :error="errors[0]">
|
||||
<input
|
||||
v-model="passwordForm.password"
|
||||
:placeholder="$t('page_create_password.label_new_pass')"
|
||||
type="password"
|
||||
class="focus-border-theme input-dark"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<ValidationProvider tag="div" mode="passive" name="Confirm Your Password" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('page_create_password.label_confirm_pass')" :error="errors[0]">
|
||||
<input v-model="passwordForm.password_confirmation" :placeholder="$t('page_create_password.label_confirm_pass')" type="password" class="focus-border-theme input-dark" :class="{'border-red': errors[0]}" />
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
<ValidationProvider tag="div" mode="passive" name="Confirm Your Password" rules="required" v-slot="{ errors }">
|
||||
<AppInputText :title="$t('page_create_password.label_confirm_pass')" :error="errors[0]">
|
||||
<input
|
||||
v-model="passwordForm.password_confirmation"
|
||||
:placeholder="$t('page_create_password.label_confirm_pass')"
|
||||
type="password"
|
||||
class="focus-border-theme input-dark"
|
||||
:class="{ 'border-red': errors[0] }"
|
||||
/>
|
||||
</AppInputText>
|
||||
</ValidationProvider>
|
||||
|
||||
<ButtonBase type="submit" button-style="theme" class="sm:w-auto w-full">
|
||||
{{ $t('profile.store_pass') }}
|
||||
</ButtonBase>
|
||||
</ValidationObserver>
|
||||
<ButtonBase type="submit" button-style="theme" class="w-full sm:w-auto">
|
||||
{{ $t('profile.store_pass') }}
|
||||
</ButtonBase>
|
||||
</ValidationObserver>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {ValidationProvider, ValidationObserver} from 'vee-validate/dist/vee-validate.full'
|
||||
import SwitchInput from "../../components/Others/Forms/SwitchInput";
|
||||
import FormLabel from "../../components/Others/Forms/FormLabel";
|
||||
import ButtonBase from "../../components/FilesView/ButtonBase";
|
||||
import InfoBox from "../../components/Others/Forms/InfoBox";
|
||||
import AppInputSwitch from "../../components/Admin/AppInputSwitch"
|
||||
import AppInputButton from "../../components/Admin/AppInputButton"
|
||||
import AppInputText from "../../components/Admin/AppInputText"
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {XIcon, Trash2Icon} from 'vue-feather-icons'
|
||||
import {events} from '../../bus'
|
||||
import {mapGetters} from 'vuex'
|
||||
import axios from 'axios'
|
||||
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
|
||||
import SwitchInput from '../../components/Others/Forms/SwitchInput'
|
||||
import FormLabel from '../../components/Others/Forms/FormLabel'
|
||||
import ButtonBase from '../../components/FilesView/ButtonBase'
|
||||
import InfoBox from '../../components/Others/Forms/InfoBox'
|
||||
import AppInputSwitch from '../../components/Admin/AppInputSwitch'
|
||||
import AppInputButton from '../../components/Admin/AppInputButton'
|
||||
import AppInputText from '../../components/Admin/AppInputText'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { XIcon, Trash2Icon } from 'vue-feather-icons'
|
||||
import { events } from '../../bus'
|
||||
import { mapGetters } from 'vuex'
|
||||
import axios from 'axios'
|
||||
|
||||
export default {
|
||||
name: 'Password',
|
||||
components: {
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AppInputButton,
|
||||
AppInputSwitch,
|
||||
AppInputText,
|
||||
SwitchInput,
|
||||
ButtonBase,
|
||||
FormLabel,
|
||||
Trash2Icon,
|
||||
required,
|
||||
InfoBox,
|
||||
XIcon,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'user',
|
||||
])
|
||||
},
|
||||
watch: {
|
||||
'user.data.attributes.two_factor_authentication': function (val) {
|
||||
val ? this.enable2faPopup() : this.disable2faPopup()
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
passwordForm: {
|
||||
current: undefined,
|
||||
password: undefined,
|
||||
password_confirmation: undefined,
|
||||
},
|
||||
isLoading: false,
|
||||
tokens: [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async resetPassword() {
|
||||
export default {
|
||||
name: 'Password',
|
||||
components: {
|
||||
ValidationProvider,
|
||||
ValidationObserver,
|
||||
AppInputButton,
|
||||
AppInputSwitch,
|
||||
AppInputText,
|
||||
SwitchInput,
|
||||
ButtonBase,
|
||||
FormLabel,
|
||||
Trash2Icon,
|
||||
required,
|
||||
InfoBox,
|
||||
XIcon,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['user']),
|
||||
},
|
||||
watch: {
|
||||
'user.data.attributes.two_factor_authentication': function (val) {
|
||||
val ? this.enable2faPopup() : this.disable2faPopup()
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
passwordForm: {
|
||||
current: undefined,
|
||||
password: undefined,
|
||||
password_confirmation: undefined,
|
||||
},
|
||||
isLoading: false,
|
||||
tokens: [],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async resetPassword() {
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.password.validate()
|
||||
|
||||
// Validate fields
|
||||
const isValid = await this.$refs.password.validate();
|
||||
if (!isValid) return
|
||||
|
||||
if (!isValid) return;
|
||||
// Send request to get user reset link
|
||||
axios
|
||||
.post(this.$store.getters.api + '/user/password', this.passwordForm)
|
||||
.then(() => {
|
||||
// Reset inputs
|
||||
this.passwordForm = {
|
||||
current: undefined,
|
||||
password: undefined,
|
||||
password_confirmation: undefined,
|
||||
}
|
||||
|
||||
// Send request to get user reset link
|
||||
axios
|
||||
.post(this.$store.getters.api + '/user/password', this.passwordForm)
|
||||
.then(() => {
|
||||
// Reset errors
|
||||
this.$refs.password.reset()
|
||||
|
||||
// Reset inputs
|
||||
this.passwordForm = {
|
||||
current: undefined,
|
||||
password: undefined,
|
||||
password_confirmation: undefined,
|
||||
}
|
||||
// Show success message
|
||||
events.$emit('success:open', {
|
||||
title: this.$t('popup_pass_changed.title'),
|
||||
message: this.$t('popup_pass_changed.message'),
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
if (error.response.status === 422) {
|
||||
if (error.response.data.errors['password']) {
|
||||
this.$refs.password.setErrors({
|
||||
'New Password': error.response.data.errors['password'],
|
||||
})
|
||||
}
|
||||
|
||||
// Reset errors
|
||||
this.$refs.password.reset()
|
||||
if (error.response.data.errors['current']) {
|
||||
this.$refs.password.setErrors({
|
||||
'Current Password': error.response.data.errors['current'],
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
getPersonalAccessTokens() {
|
||||
axios
|
||||
.get('/api/user/tokens')
|
||||
.then((response) => {
|
||||
this.tokens = response.data
|
||||
})
|
||||
.catch(() => this.$isSomethingWrong())
|
||||
},
|
||||
showRecoveryCodes() {
|
||||
events.$emit('popup:open', {
|
||||
name: 'confirm-password',
|
||||
options: {
|
||||
action: 'get-recovery-codes',
|
||||
},
|
||||
})
|
||||
},
|
||||
enable2faPopup() {
|
||||
events.$emit('popup:open', {
|
||||
name: 'confirm-password',
|
||||
options: {
|
||||
action: 'two-factor-qr-setup',
|
||||
},
|
||||
})
|
||||
},
|
||||
disable2faPopup() {
|
||||
events.$emit('popup:open', {
|
||||
name: 'confirm-password',
|
||||
options: {
|
||||
action: 'disable-2fa',
|
||||
},
|
||||
})
|
||||
},
|
||||
confirmDeleteToken(token) {
|
||||
events.$emit('confirm:open', {
|
||||
title: this.$t('popup_delete_personal_token.title'),
|
||||
message: this.$t('popup_delete_personal_token.description'),
|
||||
action: {
|
||||
id: token.id,
|
||||
operation: 'delete-personal-access-token',
|
||||
},
|
||||
})
|
||||
},
|
||||
openCreateTokenPopup() {
|
||||
events.$emit('popup:open', { name: 'create-personal-token' })
|
||||
},
|
||||
formatDate(date) {
|
||||
return new Intl.DateTimeFormat('en').format(new Date(date))
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getPersonalAccessTokens()
|
||||
|
||||
// Show success message
|
||||
events.$emit('success:open', {
|
||||
title: this.$t('popup_pass_changed.title'),
|
||||
message: this.$t('popup_pass_changed.message'),
|
||||
})
|
||||
})
|
||||
.catch(error => {
|
||||
// Actions confirmed
|
||||
events.$on('action:confirmed', (data) => {
|
||||
// Delete personal token
|
||||
if (data.operation === 'delete-personal-access-token') {
|
||||
axios
|
||||
.delete(`/api/user/tokens/${data.id}`)
|
||||
.then(() => {
|
||||
this.tokens = this.tokens.filter((tokenItem) => tokenItem.id !== data.id)
|
||||
|
||||
if (error.response.status === 422) {
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('personal_token.token_deleted'),
|
||||
})
|
||||
})
|
||||
.catch(() => this.$isSomethingWrong())
|
||||
}
|
||||
})
|
||||
|
||||
if (error.response.data.errors['password']) {
|
||||
this.$refs.password.setErrors({
|
||||
'New Password': error.response.data.errors['password']
|
||||
});
|
||||
}
|
||||
// Password confirmed
|
||||
events.$on('password:confirmed', (args) => {
|
||||
// Get recovery tokens
|
||||
if (args.options.action === 'get-recovery-codes') {
|
||||
events.$emit('popup:open', {
|
||||
name: 'two-factor-recovery-codes',
|
||||
})
|
||||
}
|
||||
|
||||
if (error.response.data.errors['current']) {
|
||||
this.$refs.password.setErrors({
|
||||
'Current Password': error.response.data.errors['current']
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
getPersonalAccessTokens() {
|
||||
axios.get('/api/user/tokens')
|
||||
.then(response => {
|
||||
this.tokens = response.data
|
||||
})
|
||||
.catch(() => this.$isSomethingWrong())
|
||||
},
|
||||
showRecoveryCodes() {
|
||||
events.$emit('popup:open', {
|
||||
name: 'confirm-password',
|
||||
options: {
|
||||
action: 'get-recovery-codes',
|
||||
}
|
||||
})
|
||||
},
|
||||
enable2faPopup() {
|
||||
events.$emit('popup:open', {
|
||||
name: 'confirm-password',
|
||||
options: {
|
||||
action: 'two-factor-qr-setup',
|
||||
}
|
||||
})
|
||||
},
|
||||
disable2faPopup() {
|
||||
events.$emit('popup:open', {
|
||||
name: 'confirm-password',
|
||||
options: {
|
||||
action: 'disable-2fa',
|
||||
}
|
||||
})
|
||||
},
|
||||
confirmDeleteToken(token) {
|
||||
events.$emit('confirm:open', {
|
||||
title: this.$t('popup_delete_personal_token.title'),
|
||||
message: this.$t('popup_delete_personal_token.description'),
|
||||
action: {
|
||||
id: token.id,
|
||||
operation: 'delete-personal-access-token'
|
||||
}
|
||||
})
|
||||
},
|
||||
openCreateTokenPopup() {
|
||||
events.$emit('popup:open', {name: 'create-personal-token'})
|
||||
},
|
||||
formatDate(date) {
|
||||
return new Intl.DateTimeFormat('en').format(new Date(date))
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getPersonalAccessTokens()
|
||||
// Get 2fa qr code
|
||||
if (args.options.action === 'two-factor-qr-setup') {
|
||||
events.$emit('popup:open', { name: 'two-factor-qr-setup' })
|
||||
}
|
||||
|
||||
// Actions confirmed
|
||||
events.$on('action:confirmed', data => {
|
||||
// Get 2fa qr code
|
||||
if (args.options.action === 'disable-2fa') {
|
||||
axios
|
||||
.delete('/user/two-factor-authentication')
|
||||
.then(() => {
|
||||
this.$store.commit('CHANGE_TWO_FACTOR_AUTHENTICATION_STATE', false)
|
||||
})
|
||||
.catch(() => {
|
||||
this.$isSomethingWrong()
|
||||
})
|
||||
.finally(() => {
|
||||
this.$closePopup()
|
||||
|
||||
// Delete personal token
|
||||
if (data.operation === 'delete-personal-access-token') {
|
||||
axios.delete(`/api/user/tokens/${data.id}`)
|
||||
.then(() => {
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('popup_2fa.toaster_disabled'),
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
this.tokens = this.tokens.filter(tokenItem => tokenItem.id !== data.id)
|
||||
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('personal_token.token_deleted'),
|
||||
})
|
||||
})
|
||||
.catch(() => this.$isSomethingWrong())
|
||||
}
|
||||
})
|
||||
|
||||
// Password confirmed
|
||||
events.$on('password:confirmed', args => {
|
||||
|
||||
// Get recovery tokens
|
||||
if (args.options.action === 'get-recovery-codes') {
|
||||
events.$emit('popup:open', {name: 'two-factor-recovery-codes'})
|
||||
}
|
||||
|
||||
// Get 2fa qr code
|
||||
if (args.options.action === 'two-factor-qr-setup') {
|
||||
events.$emit('popup:open', {name: 'two-factor-qr-setup'})
|
||||
}
|
||||
|
||||
// Get 2fa qr code
|
||||
if (args.options.action === 'disable-2fa') {
|
||||
axios
|
||||
.delete('/user/two-factor-authentication')
|
||||
.then(() => {
|
||||
this.$store.commit('CHANGE_TWO_FACTOR_AUTHENTICATION_STATE', false)
|
||||
})
|
||||
.catch(() => {
|
||||
this.$isSomethingWrong()
|
||||
})
|
||||
.finally(() => {
|
||||
this.$closePopup()
|
||||
|
||||
events.$emit('toaster', {
|
||||
type: 'success',
|
||||
message: this.$t('popup_2fa.toaster_disabled'),
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
events.$on('reload-personal-access-tokens', () => this.getPersonalAccessTokens())
|
||||
},
|
||||
destroyed() {
|
||||
events.$off('action:confirmed')
|
||||
},
|
||||
}
|
||||
events.$on('reload-personal-access-tokens', () => this.getPersonalAccessTokens())
|
||||
},
|
||||
destroyed() {
|
||||
events.$off('action:confirmed')
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -2,210 +2,223 @@
|
||||
<div>
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Account Settings') }}
|
||||
</FormLabel>
|
||||
{{ $t('Account Settings') }}
|
||||
</FormLabel>
|
||||
|
||||
<div class="md:flex justify-items md:space-x-4">
|
||||
<AppInputText :title="$t('First Name')" class="w-full">
|
||||
<input
|
||||
@keyup="updateFirstName"
|
||||
v-model="user.data.relationships.settings.data.attributes.first_name"
|
||||
:placeholder="$t('page_registration.placeholder_name')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('Last Name')" class="w-full">
|
||||
<input
|
||||
@keyup="updateLastName"
|
||||
v-model="user.data.relationships.settings.data.attributes.last_name"
|
||||
:placeholder="$t('page_registration.placeholder_name')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
<div class="justify-items md:flex md:space-x-4">
|
||||
<AppInputText :title="$t('First Name')" class="w-full">
|
||||
<input
|
||||
@keyup="updateFirstName"
|
||||
v-model="user.data.relationships.settings.data.attributes.first_name"
|
||||
:placeholder="$t('page_registration.placeholder_name')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('Last Name')" class="w-full">
|
||||
<input
|
||||
@keyup="updateLastName"
|
||||
v-model="user.data.relationships.settings.data.attributes.last_name"
|
||||
:placeholder="$t('page_registration.placeholder_name')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
|
||||
<AppInputText :title="$t('GMT')" :is-last="true">
|
||||
<AppInputText :title="$t('GMT')" :is-last="true">
|
||||
<SelectInput
|
||||
@input="$updateText('/user/settings', 'timezone', user.data.relationships.settings.data.attributes.timezone)"
|
||||
v-model="user.data.relationships.settings.data.attributes.timezone"
|
||||
:default="user.data.relationships.settings.data.attributes.timezone"
|
||||
:options="timezones"
|
||||
:placeholder="$t('user_settings.timezone_plac')" />
|
||||
@input="$updateText('/user/settings', 'timezone', user.data.relationships.settings.data.attributes.timezone)"
|
||||
v-model="user.data.relationships.settings.data.attributes.timezone"
|
||||
:default="user.data.relationships.settings.data.attributes.timezone"
|
||||
:options="timezones"
|
||||
:placeholder="$t('user_settings.timezone_plac')"
|
||||
/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Appearance') }}
|
||||
</FormLabel>
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('Appearance') }}
|
||||
</FormLabel>
|
||||
|
||||
<AppInputText :title="$t('Theme Mode')" :description="$t('Set your theme mode on dark, light or based on your system settings.')" :is-last="! $isApple()">
|
||||
<div class="md:flex items-center md:space-x-6 md:space-x-4 md:space-y-0 space-y-4">
|
||||
<div
|
||||
v-for="(theme, i) in themeSetup"
|
||||
:key="i"
|
||||
:title="theme.title"
|
||||
@click="$store.dispatch('toggleThemeMode', theme.type)"
|
||||
class="w-full rounded-xl shadow-lg overflow-hidden cursor-pointer border-3"
|
||||
:class="{'border-theme': config.defaultThemeMode === theme.type, 'border-transparent': config.defaultThemeMode !== theme.type}"
|
||||
>
|
||||
<img :src="theme.image" :alt="theme.type">
|
||||
</div>
|
||||
</div>
|
||||
<AppInputText :title="$t('Theme Mode')" :description="$t('Set your theme mode on dark, light or based on your system settings.')" :is-last="!$isApple()">
|
||||
<div class="items-center space-y-4 md:flex md:space-x-6 md:space-x-4 md:space-y-0">
|
||||
<div
|
||||
v-for="(theme, i) in themeSetup"
|
||||
:key="i"
|
||||
:title="theme.title"
|
||||
@click="$store.dispatch('toggleThemeMode', theme.type)"
|
||||
class="w-full cursor-pointer overflow-hidden rounded-xl border-3 shadow-lg"
|
||||
:class="{
|
||||
'border-theme': config.defaultThemeMode === theme.type,
|
||||
'border-transparent': config.defaultThemeMode !== theme.type,
|
||||
}"
|
||||
>
|
||||
<img :src="theme.image" :alt="theme.type" />
|
||||
</div>
|
||||
</div>
|
||||
</AppInputText>
|
||||
|
||||
<AppInputText v-if="$isApple()" :title="$t('Default Emojis')" :description="$t('Set your default emojis for your folder custom icons. You can set Twemoji or default Apple emojis.')" :is-last="true">
|
||||
<div class="md:flex items-center md:space-x-6 md:space-x-4 md:space-y-0 space-y-4">
|
||||
<div
|
||||
v-for="(emoji, i) in emojiSetup"
|
||||
:key="i"
|
||||
:title="emoji.title"
|
||||
@click="$store.dispatch('toggleEmojiType', emoji.type)"
|
||||
class="w-full rounded-xl shadow-lg overflow-hidden cursor-pointer border-3"
|
||||
:class="{'border-theme': currentEmojis === emoji.type, 'border-transparent': currentEmojis !== emoji.type}"
|
||||
>
|
||||
<img :src="isDarkMode ? emoji.image.dark : emoji.image.light" :alt="emoji.type">
|
||||
</div>
|
||||
</div>
|
||||
</AppInputText>
|
||||
</div>
|
||||
<AppInputText
|
||||
v-if="$isApple()"
|
||||
:title="$t('Default Emojis')"
|
||||
:description="$t('Set your default emojis for your folder custom icons. You can set Twemoji or default Apple emojis.')"
|
||||
:is-last="true"
|
||||
>
|
||||
<div class="items-center space-y-4 md:flex md:space-x-6 md:space-x-4 md:space-y-0">
|
||||
<div
|
||||
v-for="(emoji, i) in emojiSetup"
|
||||
:key="i"
|
||||
:title="emoji.title"
|
||||
@click="$store.dispatch('toggleEmojiType', emoji.type)"
|
||||
class="w-full cursor-pointer overflow-hidden rounded-xl border-3 shadow-lg"
|
||||
:class="{
|
||||
'border-theme': currentEmojis === emoji.type,
|
||||
'border-transparent': currentEmojis !== emoji.type,
|
||||
}"
|
||||
>
|
||||
<img :src="isDarkMode ? emoji.image.dark : emoji.image.light" :alt="emoji.type" />
|
||||
</div>
|
||||
</div>
|
||||
</AppInputText>
|
||||
</div>
|
||||
|
||||
<div class="card shadow-card">
|
||||
<FormLabel>
|
||||
{{ $t('user_settings.title_billing') }}
|
||||
</FormLabel>
|
||||
<AppInputText :title="$t('user_settings.address')">
|
||||
<input @keyup="$updateText('/user/settings', 'address', user.data.relationships.settings.data.attributes.address)"
|
||||
v-model="user.data.relationships.settings.data.attributes.address"
|
||||
:placeholder="$t('user_settings.address_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
<input
|
||||
@keyup="$updateText('/user/settings', 'address', user.data.relationships.settings.data.attributes.address)"
|
||||
v-model="user.data.relationships.settings.data.attributes.address"
|
||||
:placeholder="$t('user_settings.address_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
<div class="flex space-x-4">
|
||||
<AppInputText :title="$t('user_settings.city')" class="w-full">
|
||||
<input @keyup="$updateText('/user/settings', 'city', user.data.relationships.settings.data.attributes.city)"
|
||||
v-model="user.data.relationships.settings.data.attributes.city"
|
||||
:placeholder="$t('user_settings.city_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
<input
|
||||
@keyup="$updateText('/user/settings', 'city', user.data.relationships.settings.data.attributes.city)"
|
||||
v-model="user.data.relationships.settings.data.attributes.city"
|
||||
:placeholder="$t('user_settings.city_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('user_settings.postal_code')" class="w-full">
|
||||
<input @keyup="$updateText('/user/settings', 'postal_code', user.data.relationships.settings.data.attributes.postal_code)"
|
||||
v-model="user.data.relationships.settings.data.attributes.postal_code"
|
||||
:placeholder="$t('user_settings.postal_code_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
<input
|
||||
@keyup="$updateText('/user/settings', 'postal_code', user.data.relationships.settings.data.attributes.postal_code)"
|
||||
v-model="user.data.relationships.settings.data.attributes.postal_code"
|
||||
:placeholder="$t('user_settings.postal_code_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
<AppInputText :title="$t('user_settings.country')">
|
||||
<SelectInput @input="$updateText('/user/settings', 'country', user.data.relationships.settings.data.attributes.country)"
|
||||
v-model="user.data.relationships.settings.data.attributes.country"
|
||||
:default="user.data.relationships.settings.data.attributes.country"
|
||||
:options="countries"
|
||||
:placeholder="$t('user_settings.country_plac')"
|
||||
/>
|
||||
<SelectInput
|
||||
@input="$updateText('/user/settings', 'country', user.data.relationships.settings.data.attributes.country)"
|
||||
v-model="user.data.relationships.settings.data.attributes.country"
|
||||
:default="user.data.relationships.settings.data.attributes.country"
|
||||
:options="countries"
|
||||
:placeholder="$t('user_settings.country_plac')"
|
||||
/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('user_settings.state')" :description="$t('State, county, province, or region.')">
|
||||
<input @keyup="$updateText('/user/settings', 'state', user.data.relationships.settings.data.attributes.state)"
|
||||
v-model="user.data.relationships.settings.data.attributes.state"
|
||||
:placeholder="$t('user_settings.state_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
<input
|
||||
@keyup="$updateText('/user/settings', 'state', user.data.relationships.settings.data.attributes.state)"
|
||||
v-model="user.data.relationships.settings.data.attributes.state"
|
||||
:placeholder="$t('user_settings.state_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
<AppInputText :title="$t('user_settings.phone_number')" :is-last="true">
|
||||
<input @keyup="$updateText('/user/settings', 'phone_number', user.data.relationships.settings.data.attributes.phone_number)"
|
||||
v-model="user.data.relationships.settings.data.attributes.phone_number"
|
||||
:placeholder="$t('user_settings.phone_number_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
<input
|
||||
@keyup="$updateText('/user/settings', 'phone_number', user.data.relationships.settings.data.attributes.phone_number)"
|
||||
v-model="user.data.relationships.settings.data.attributes.phone_number"
|
||||
:placeholder="$t('user_settings.phone_number_plac')"
|
||||
type="text"
|
||||
class="focus-border-theme input-dark"
|
||||
/>
|
||||
</AppInputText>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import AppInputText from "../../components/Admin/AppInputText";
|
||||
import SelectInput from "../../components/Others/Forms/SelectInput";
|
||||
import FormLabel from "../../components/Others/Forms/FormLabel";
|
||||
import {required} from 'vee-validate/dist/rules'
|
||||
import {mapGetters} from 'vuex'
|
||||
import AppInputText from '../../components/Admin/AppInputText'
|
||||
import SelectInput from '../../components/Others/Forms/SelectInput'
|
||||
import FormLabel from '../../components/Others/Forms/FormLabel'
|
||||
import { required } from 'vee-validate/dist/rules'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Settings',
|
||||
components: {
|
||||
AppInputText,
|
||||
SelectInput,
|
||||
FormLabel,
|
||||
required,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'isDarkMode',
|
||||
'countries',
|
||||
'timezones',
|
||||
'config',
|
||||
]),
|
||||
currentEmojis() {
|
||||
return this.config.defaultEmoji
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
user: this.$store.getters.user,
|
||||
isLoading: false,
|
||||
themeSetup: [
|
||||
{
|
||||
title: this.$t('Light mode'),
|
||||
type: 'light',
|
||||
image: '/assets/setup/light-mode.jpg',
|
||||
},
|
||||
{
|
||||
title: this.$t('Dark mode'),
|
||||
type: 'dark',
|
||||
image: '/assets/setup/dark-mode.jpg',
|
||||
},
|
||||
{
|
||||
title: this.$t('Based on system settings'),
|
||||
type: 'system',
|
||||
image: '/assets/setup/system-mode.jpg',
|
||||
},
|
||||
],
|
||||
emojiSetup: [
|
||||
{
|
||||
title: 'Twemoji',
|
||||
type: 'twemoji',
|
||||
image: {
|
||||
dark: '/assets/setup/twemoji-preview-dark.jpg',
|
||||
light: '/assets/setup/twemoji-preview.jpg',
|
||||
}
|
||||
},
|
||||
{
|
||||
title: 'Applemoji',
|
||||
type: 'applemoji',
|
||||
image: {
|
||||
dark: '/assets/setup/applemoji-preview-dark.jpg',
|
||||
light: '/assets/setup/applemoji-preview.jpg',
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateFirstName() {
|
||||
this.$store.commit('UPDATE_FIRST_NAME', this.user.data.relationships.settings.data.attributes.first_name)
|
||||
this.$updateText('/user/settings', 'first_name', this.user.data.relationships.settings.data.attributes.first_name)
|
||||
},
|
||||
updateLastName() {
|
||||
this.$store.commit('UPDATE_LAST_NAME', this.user.data.relationships.settings.data.attributes.last_name)
|
||||
this.$updateText('/user/settings', 'last_name', this.user.data.relationships.settings.data.attributes.last_name)
|
||||
}
|
||||
},
|
||||
}
|
||||
export default {
|
||||
name: 'Settings',
|
||||
components: {
|
||||
AppInputText,
|
||||
SelectInput,
|
||||
FormLabel,
|
||||
required,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['isDarkMode', 'countries', 'timezones', 'config']),
|
||||
currentEmojis() {
|
||||
return this.config.defaultEmoji
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
user: this.$store.getters.user,
|
||||
isLoading: false,
|
||||
themeSetup: [
|
||||
{
|
||||
title: this.$t('Light mode'),
|
||||
type: 'light',
|
||||
image: '/assets/setup/light-mode.jpg',
|
||||
},
|
||||
{
|
||||
title: this.$t('Dark mode'),
|
||||
type: 'dark',
|
||||
image: '/assets/setup/dark-mode.jpg',
|
||||
},
|
||||
{
|
||||
title: this.$t('Based on system settings'),
|
||||
type: 'system',
|
||||
image: '/assets/setup/system-mode.jpg',
|
||||
},
|
||||
],
|
||||
emojiSetup: [
|
||||
{
|
||||
title: 'Twemoji',
|
||||
type: 'twemoji',
|
||||
image: {
|
||||
dark: '/assets/setup/twemoji-preview-dark.jpg',
|
||||
light: '/assets/setup/twemoji-preview.jpg',
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Applemoji',
|
||||
type: 'applemoji',
|
||||
image: {
|
||||
dark: '/assets/setup/applemoji-preview-dark.jpg',
|
||||
light: '/assets/setup/applemoji-preview.jpg',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateFirstName() {
|
||||
this.$store.commit('UPDATE_FIRST_NAME', this.user.data.relationships.settings.data.attributes.first_name)
|
||||
this.$updateText('/user/settings', 'first_name', this.user.data.relationships.settings.data.attributes.first_name)
|
||||
},
|
||||
updateLastName() {
|
||||
this.$store.commit('UPDATE_LAST_NAME', this.user.data.relationships.settings.data.attributes.last_name)
|
||||
this.$updateText('/user/settings', 'last_name', this.user.data.relationships.settings.data.attributes.last_name)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -1,91 +1,88 @@
|
||||
<template>
|
||||
<PageTab>
|
||||
<div v-if="distribution" class="card shadow-card">
|
||||
<FormLabel icon="hard-drive">
|
||||
<div v-if="distribution" class="card shadow-card">
|
||||
<FormLabel icon="hard-drive">
|
||||
{{ $t('Storage Usage') }}
|
||||
</FormLabel>
|
||||
|
||||
<b class="sm:text-3xl text-2xl font-extrabold -mt-3 block">
|
||||
{{ storage.data.attributes.used }}
|
||||
</b>
|
||||
<b class="-mt-3 block text-2xl font-extrabold sm:text-3xl">
|
||||
{{ storage.data.attributes.used }}
|
||||
</b>
|
||||
|
||||
<b v-if="config.subscriptionType === 'fixed' || (config.subscriptionType === 'none' && config.storageLimit)" class="mt-0.5 block text-sm text-gray-400">
|
||||
{{ $t('Total of') }} {{ storage.data.attributes.capacity }} {{ $t('Used') }}
|
||||
</b>
|
||||
<b v-if="config.subscriptionType === 'fixed' || (config.subscriptionType === 'none' && config.storageLimit)" class="mt-0.5 block text-sm text-gray-400">
|
||||
{{ $t('Total of') }} {{ storage.data.attributes.capacity }}
|
||||
{{ $t('Used') }}
|
||||
</b>
|
||||
|
||||
<ProgressLine :data="distribution" class="mt-5" />
|
||||
</div>
|
||||
<div v-if="distribution" class="card shadow-card">
|
||||
<FormLabel icon="hard-drive">
|
||||
<ProgressLine :data="distribution" class="mt-5" />
|
||||
</div>
|
||||
<div v-if="distribution" class="card shadow-card">
|
||||
<FormLabel icon="hard-drive">
|
||||
{{ $t('Upload') }}
|
||||
</FormLabel>
|
||||
|
||||
<b class="sm:text-3xl text-2xl font-extrabold -mt-3 block mb-0.5">
|
||||
{{ storage.data.meta.traffic.upload }}
|
||||
</b>
|
||||
<b class="-mt-3 mb-0.5 block text-2xl font-extrabold sm:text-3xl">
|
||||
{{ storage.data.meta.traffic.upload }}
|
||||
</b>
|
||||
|
||||
<b class="mb-3 block text-sm text-gray-400 mb-5">
|
||||
{{ $t('In last 45 days') }}
|
||||
</b>
|
||||
<b class="mb-3 mb-5 block text-sm text-gray-400">
|
||||
{{ $t('In last 45 days') }}
|
||||
</b>
|
||||
|
||||
<BarChart :data="storage.data.meta.traffic.chart.upload" color="#FFBD2D" />
|
||||
</div>
|
||||
<div v-if="distribution" class="card shadow-card">
|
||||
<FormLabel icon="hard-drive">
|
||||
<BarChart :data="storage.data.meta.traffic.chart.upload" color="#FFBD2D" />
|
||||
</div>
|
||||
<div v-if="distribution" class="card shadow-card">
|
||||
<FormLabel icon="hard-drive">
|
||||
{{ $t('Download') }}
|
||||
</FormLabel>
|
||||
|
||||
<b class="sm:text-3xl text-2xl font-extrabold -mt-3 block mb-0.5">
|
||||
{{ storage.data.meta.traffic.download }}
|
||||
</b>
|
||||
<b class="-mt-3 mb-0.5 block text-2xl font-extrabold sm:text-3xl">
|
||||
{{ storage.data.meta.traffic.download }}
|
||||
</b>
|
||||
|
||||
<b class="mb-3 block text-sm text-gray-400 mb-5">
|
||||
{{ $t('In last 45 days') }}
|
||||
</b>
|
||||
<b class="mb-3 mb-5 block text-sm text-gray-400">
|
||||
{{ $t('In last 45 days') }}
|
||||
</b>
|
||||
|
||||
<BarChart :data="storage.data.meta.traffic.chart.download" color="#9d66fe" />
|
||||
</div>
|
||||
<BarChart :data="storage.data.meta.traffic.chart.download" color="#9d66fe" />
|
||||
</div>
|
||||
</PageTab>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ProgressLine from "../../components/Admin/ProgressLine";
|
||||
import FormLabel from "../../components/Others/Forms/FormLabel";
|
||||
import PageTab from "../../components/Others/Layout/PageTab";
|
||||
import axios from 'axios'
|
||||
import BarChart from "../../components/UI/BarChart";
|
||||
import {mapGetters} from "vuex";
|
||||
import ProgressLine from '../../components/Admin/ProgressLine'
|
||||
import FormLabel from '../../components/Others/Forms/FormLabel'
|
||||
import PageTab from '../../components/Others/Layout/PageTab'
|
||||
import axios from 'axios'
|
||||
import BarChart from '../../components/UI/BarChart'
|
||||
import { mapGetters } from 'vuex'
|
||||
|
||||
export default {
|
||||
name: 'Storage',
|
||||
components: {
|
||||
BarChart,
|
||||
ProgressLine,
|
||||
FormLabel,
|
||||
PageTab,
|
||||
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'config'
|
||||
])
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
distribution: undefined,
|
||||
storage: undefined
|
||||
}
|
||||
},
|
||||
created() {
|
||||
axios.get('/api/user/storage')
|
||||
.then(response => {
|
||||
this.distribution = this.$mapStorageUsage(response.data)
|
||||
|
||||
this.storage = response.data
|
||||
|
||||
this.isLoading = false
|
||||
})
|
||||
export default {
|
||||
name: 'Storage',
|
||||
components: {
|
||||
BarChart,
|
||||
ProgressLine,
|
||||
FormLabel,
|
||||
PageTab,
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['config']),
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: true,
|
||||
distribution: undefined,
|
||||
storage: undefined,
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
axios.get('/api/user/storage').then((response) => {
|
||||
this.distribution = this.$mapStorageUsage(response.data)
|
||||
|
||||
this.storage = response.data
|
||||
|
||||
this.isLoading = false
|
||||
})
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user