setup wizard refactoring

This commit is contained in:
Čarodej
2022-02-09 14:04:51 +01:00
parent a9e4daed35
commit a6940379cb
34 changed files with 548 additions and 1856 deletions

View File

@@ -4,6 +4,7 @@ APP_KEY=base64:sB1YuKsbWv7MdWugb9ZsYBqv2QZJ+QOuHZHEddOsUuo=
APP_DEBUG=true
APP_URL=http://localhost
APP_DEMO=false
IS_SETUP_WIZARD_DEMO=false
LOG_CHANNEL=daily

View File

@@ -36,7 +36,8 @@
"spatie/laravel-tail": "^4.3.3",
"stechstudio/laravel-zipstream": "^4.5",
"teamtnt/laravel-scout-tntsearch-driver": "^11.5.0.0",
"vimeo/psalm": "^4.11.2"
"vimeo/psalm": "^4.11.2",
"ext-pdo": "*"
},
"require-dev": {
"ext-json": "*",

View File

@@ -85,13 +85,12 @@ export default {
// Get installation state
let installation = this.$root.$data.config.installation
if (['setup-disclaimer', 'setup-database'].includes(installation)) this.isLoaded = true
if (['setup-disclaimer', 'setup-database'].includes(installation))
this.isLoaded = true
// Redirect to database verify code
if (installation === 'setup-database') this.$router.push({ name: 'StatusCheck' })
// Redirect to starting installation process
if (installation === 'setup-disclaimer') this.$router.push({ name: 'InstallationDisclaimer' })
//if (installation === 'setup-database')
//this.$router.push({ name: 'StatusCheck' })
if (installation === 'setup-done')
this.$store.dispatch('getLanguageTranslations', this.$root.$data.config.locale).then(() => {
@@ -100,11 +99,6 @@ export default {
// Store config to vuex
this.$store.commit('INIT', {
config: this.$root.$data.config,
rootDirectory: {
name: this.$t('locations.home'),
location: 'base',
id: undefined,
},
})
})
},

View File

@@ -1,5 +1,5 @@
<template>
<div class="flex items-center justify-center px-5 md:px-0">
<div class="flex items-center justify-center px-2.5 md:px-6">
<slot></slot>
</div>
</template>

View File

@@ -1,5 +1,5 @@
<template>
<div class="input-wrapper">
<div>
<div class="switch-content">
<label class="input-label" v-if="label"> {{ label }}: </label>
<small class="input-info" v-if="info">

View File

@@ -49,7 +49,7 @@
</ValidationProvider>
<!--Member list-->
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Members" rules="required" v-slot="{ errors }">
<ValidationProvider tag="div" mode="passive" name="Members" rules="required" v-slot="{ errors }">
<AppInputText :title="$t('Your Members')" :error="errors[0]" :is-last="true">
<span v-if="errors[0]" class="error-message" style="margin-top: -5px">
{{ $t('Please add at least one member.') }}

View File

@@ -37,7 +37,7 @@
</ValidationProvider>
<!--Member list-->
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Members" v-slot="{ errors }">
<ValidationProvider tag="div" mode="passive" name="Members" v-slot="{ errors }">
<label class="input-label">{{ $t('Your Members') }}:</label>
<span v-if="errors[0]" class="error-message" style="margin-top: -5px">{{ $t('Please add at least one member.') }}</span>
<TeamList v-model="members" />

View File

@@ -31,46 +31,6 @@ const routesMaintenance = [
requiresAuth: false,
},
},
{
name: 'InstallationDisclaimer',
path: '/setup-wizard/installation-disclaimer',
component: () => import(/* webpackChunkName: "chunks/installation-disclaimer" */ '../views/SetupWizard/InstallationDisclaimer'),
meta: {
requiresAuth: false,
},
},
{
name: 'SubscriptionService',
path: '/setup-wizard/subscription-service',
component: () => import(/* webpackChunkName: "chunks/subscription-service" */ '../views/SetupWizard/SubscriptionService'),
meta: {
requiresAuth: false,
},
},
{
name: 'StripeCredentials',
path: '/setup-wizard/stripe-credentials',
component: () => import(/* webpackChunkName: "chunks/stripe-credentials" */ '../views/SetupWizard/StripeCredentials'),
meta: {
requiresAuth: false,
},
},
{
name: 'BillingsDetail',
path: '/setup-wizard/stripe-billings',
component: () => import(/* webpackChunkName: "chunks/billings-detail" */ '../views/SetupWizard/BillingsDetail'),
meta: {
requiresAuth: false,
},
},
{
name: 'SubscriptionPlans',
path: '/setup-wizard/stripe-plans',
component: () => import(/* webpackChunkName: "chunks/subscription-plans" */ '../views/SetupWizard/SubscriptionPlans'),
meta: {
requiresAuth: false,
},
},
{
name: 'EnvironmentSetup',
path: '/setup-wizard/environment-setup',

View File

@@ -27,7 +27,7 @@
<div class="block-wrapper">
<label>Title:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Title" rules="required" v-slot="{ errors }">
<ValidationProvider tag="div" mode="passive" name="App Title" rules="required" v-slot="{ errors }">
<input
@input="$updateText('/admin/settings', 'header_title', app.header_title)"
v-model="app.header_title"
@@ -41,7 +41,7 @@
<div class="block-wrapper">
<label>Description:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Description" rules="required" v-slot="{ errors }">
<ValidationProvider tag="div" mode="passive" name="App Description" rules="required" v-slot="{ errors }">
<textarea
@input="$updateText('/admin/settings', 'header_description', app.header_description)"
rows="2"
@@ -59,7 +59,7 @@
<FormLabel>Features Title</FormLabel>
<div class="block-wrapper">
<div class="input-wrapper">
<div>
<div class="inline-wrapper">
<div class="switch-label">
<label class="input-label"> Show section: </label>
@@ -81,7 +81,7 @@
<div class="block-wrapper">
<label>Title:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Title" rules="required" v-slot="{ errors }">
<ValidationProvider tag="div" mode="passive" name="App Title" rules="required" v-slot="{ errors }">
<input
@input="$updateText('/admin/settings', 'features_title', app.features_title)"
v-model="app.features_title"
@@ -95,7 +95,7 @@
<div class="block-wrapper">
<label>Description:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Description" rules="required" v-slot="{ errors }">
<ValidationProvider tag="div" mode="passive" name="App Description" rules="required" v-slot="{ errors }">
<textarea
@input="$updateText('/admin/settings', 'features_description', app.features_description)"
rows="2"
@@ -114,7 +114,7 @@
<FormLabel>Feature Boxes</FormLabel>
<div class="block-wrapper">
<div class="input-wrapper">
<div>
<div class="inline-wrapper">
<div class="switch-label">
<label class="input-label"> Show section: </label>
@@ -135,7 +135,7 @@
</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 }">
<ValidationProvider tag="div" mode="passive" 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"
@@ -148,7 +148,7 @@
</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 }">
<ValidationProvider tag="div" mode="passive" name="Feature Description 1" rules="required" v-slot="{ errors }">
<textarea
@input="$updateText('/admin/settings', 'feature_description_1', app.feature_description_1)"
rows="2"
@@ -161,7 +161,7 @@
</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 }">
<ValidationProvider tag="div" mode="passive" 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"
@@ -174,7 +174,7 @@
</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 }">
<ValidationProvider tag="div" mode="passive" name="Feature Description 2" rules="required" v-slot="{ errors }">
<textarea
@input="$updateText('/admin/settings', 'feature_description_2', app.feature_description_2)"
rows="2"
@@ -187,7 +187,7 @@
</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 }">
<ValidationProvider tag="div" mode="passive" 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"
@@ -200,7 +200,7 @@
</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 }">
<ValidationProvider tag="div" mode="passive" name="Feature Description 3" rules="required" v-slot="{ errors }">
<textarea
@input="$updateText('/admin/settings', 'feature_description_3', app.feature_description_3)"
rows="2"
@@ -219,7 +219,7 @@
<FormLabel>Pricing Content</FormLabel>
<div class="block-wrapper">
<div class="input-wrapper">
<div>
<div class="inline-wrapper">
<div class="switch-label">
<label class="input-label"> Show section: </label>
@@ -240,7 +240,7 @@
</div>
<div class="block-wrapper">
<label>Title:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Title" rules="required" v-slot="{ errors }">
<ValidationProvider tag="div" mode="passive" name="App Title" rules="required" v-slot="{ errors }">
<input
@input="$updateText('/admin/settings', 'pricing_title', app.pricing_title)"
v-model="app.pricing_title"
@@ -254,7 +254,7 @@
<div class="block-wrapper">
<label>Description:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Description" rules="required" v-slot="{ errors }">
<ValidationProvider tag="div" mode="passive" name="App Description" rules="required" v-slot="{ errors }">
<textarea
@input="$updateText('/admin/settings', 'pricing_description', app.pricing_description)"
rows="2"
@@ -273,7 +273,7 @@
<FormLabel>Get Started Content</FormLabel>
<div class="block-wrapper">
<div class="input-wrapper">
<div>
<div class="inline-wrapper">
<div class="switch-label">
<label class="input-label"> Show section: </label>
@@ -294,7 +294,7 @@
</div>
<div class="block-wrapper">
<label>Title:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Title" rules="required" v-slot="{ errors }">
<ValidationProvider tag="div" mode="passive" 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"
@@ -308,7 +308,7 @@
<div class="block-wrapper">
<label>Description:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Description" rules="required" v-slot="{ errors }">
<ValidationProvider tag="div" mode="passive" name="App Description" rules="required" v-slot="{ errors }">
<textarea
@input="$updateText('/admin/settings', 'get_started_description', app.get_started_description)"
rows="2"
@@ -328,7 +328,7 @@
<div class="block-wrapper">
<label>Footer content:</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="App Title" rules="required" v-slot="{ errors }">
<ValidationProvider tag="div" mode="passive" name="App Title" rules="required" v-slot="{ errors }">
<input
@input="$updateText('/admin/settings', 'footer_content', app.footer_content)"
v-model="app.footer_content"

View File

@@ -527,7 +527,11 @@ export default {
return `${this.config.host}/api/subscriptions/${service}/webhook`
},
},
mounted() {
created() {
events.$on('action:confirmed', (data) => {
if (data.operation === 'change-subscription-type') this.$updateText('/admin/settings', 'subscription_type', data.type)
})
// Set payment description
this.stripe.paymentDescription = this.config.stripe_payment_description
this.paystack.paymentDescription = this.config.paystack_payment_description
@@ -550,11 +554,6 @@ export default {
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')
},

View File

@@ -11,7 +11,7 @@
<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 }">
<ValidationProvider tag="div" mode="passive" name="E-Mail" rules="required" v-slot="{ errors }">
<input
v-model="contact.email"
:placeholder="$t('page_contact_us.form.email_plac')"
@@ -25,7 +25,7 @@
<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 }">
<ValidationProvider tag="div" mode="passive" name="Message" rules="required" v-slot="{ errors }">
<textarea
v-model="contact.message"
:placeholder="$t('page_contact_us.form.message_plac')"

View File

@@ -3,17 +3,12 @@
</template>
<script>
import { mapGetters } from 'vuex'
export default {
name: 'SetupWizard',
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>

View File

@@ -1,64 +1,54 @@
<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" />
<h1>Setup Wizard</h1>
<h2>Create your admin account.</h2>
</div>
<AuthContent name="database-credentials" :visible="true" class="!max-w-2xl mt-6 mb-12">
<Headline class="mx-auto max-w-screen-sm !mb-10" title="Setup Wizard" description="Create your admin account.">
<settings-icon size="40" class="vue-feather text-theme mx-auto animate-[spin_5s_linear_infinite] mb-3" />
</Headline>
<ValidationObserver @submit.prevent="adminAccountSubmit" ref="adminAccount" v-slot="{ invalid }" tag="form" class="form block-form">
<FormLabel>Create Admin Account</FormLabel>
<ValidationObserver @submit.prevent="adminAccountSubmit" ref="adminAccount" v-slot="{ invalid }" tag="form" class="card shadow-card text-left">
<FormLabel>
Create Admin Account
</FormLabel>
<div class="block-wrapper">
<label>Avatar (optional):</label>
<ValidationProvider tag="div" mode="passive" class="input-wrapper" name="Avatar" v-slot="{ errors }">
<ValidationProvider tag="div" mode="passive" name="Avatar" v-slot="{ errors }">
<AppInputText title="Avatar (optional)" :error="errors[0]">
<ImageInput v-model="admin.avatar" :error="errors[0]" />
</ValidationProvider>
</div>
</AppInputText>
</ValidationProvider>
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="Full Name" rules="required" v-slot="{ errors }">
<AppInputText title="Full Name" :error="errors[0]">
<input v-model="admin.name" class="focus-border-theme input-dark" placeholder="Type your full name" type="text" :class="{ 'border-red': errors[0] }" />
</AppInputText>
</ValidationProvider>
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="Email" rules="required" v-slot="{ errors }">
<AppInputText title="Email" :error="errors[0]">
<input v-model="admin.email" class="focus-border-theme input-dark" placeholder="Type your email" type="email" :class="{ 'border-red': errors[0] }" />
</AppInputText>
</ValidationProvider>
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="Password" rules="required|confirmed:confirmation" v-slot="{ errors }">
<AppInputText title="Password" :error="errors[0]">
<input v-model="admin.password" class="focus-border-theme input-dark" placeholder="Type your password" type="password" :class="{ 'border-red': errors[0] }" />
</AppInputText>
</ValidationProvider>
<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] }" />
<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" />
</div>
<ValidationProvider tag="div" name="confirmation" rules="required" vid="confirmation" v-slot="{ errors }">
<AppInputText title="Password Confirmation" :error="errors[0]" :is-last="true">
<input v-model="admin.password_confirmation" class="focus-border-theme input-dark" placeholder="Confirm your password" type="password" :class="{ 'border-red': errors[0] }" />
</AppInputText>
</ValidationProvider>
</ValidationObserver>
<AuthButton @click.native="adminAccountSubmit" class="w-full justify-center" icon="chevron-right" text="Create Admin and Login" :loading="isLoading" :disabled="isLoading" />
</AuthContent>
</AuthContentWrapper>
</template>
<script>
import AppInputText from "../../components/Admin/AppInputText";
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
import SelectInput from '../../components/Others/Forms/SelectInput'
@@ -68,8 +58,9 @@ 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 { SettingsIcon } from 'vue-feather-icons'
import Headline from "../Auth/Headline"
import { events } from '../../bus'
import axios from 'axios'
@@ -79,6 +70,7 @@ export default {
AuthContentWrapper,
ValidationProvider,
ValidationObserver,
AppInputText,
SettingsIcon,
SelectInput,
SwitchInput,
@@ -87,6 +79,7 @@ export default {
AuthButton,
FormLabel,
required,
Headline,
InfoBox,
},
data() {
@@ -192,9 +185,3 @@ export default {
},
}
</script>
<style scoped lang="scss">
@import '../../../sass/vuefilemanager/forms';
@import '../../../sass/vuefilemanager/auth';
@import '../../../sass/vuefilemanager/setup_wizard';
</style>

View File

@@ -1,131 +1,126 @@
<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.">
<settings-icon size="40" class="title-icon text-theme mx-auto" />
<AuthContent name="database-credentials" :visible="true" class="!max-w-2xl mt-6 mb-12">
<Headline class="mx-auto max-w-screen-sm !mb-10" title="Setup Wizard" description="Set up your application appearance, analytics, etc.">
<settings-icon size="40" class="vue-feather text-theme mx-auto animate-[spin_5s_linear_infinite] mb-3" />
</Headline>
<ValidationObserver @submit.prevent="appSetupSubmit" ref="appSetup" v-slot="{ invalid }" tag="form" class="form block-form">
<FormLabel>General Settings</FormLabel>
<ValidationObserver @submit.prevent="appSetupSubmit" ref="appSetup" v-slot="{ invalid }" tag="form">
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="card shadow-card text-left">
<FormLabel>General Settings</FormLabel>
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="App Title" rules="required" v-slot="{ errors }">
<AppInputText title="App Title" :error="errors[0]">
<input class="focus-border-theme input-dark" v-model="app.title" placeholder="Type your app title" type="text" :class="{ 'border-red': errors[0] }" />
</AppInputText>
</ValidationProvider>
<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]" />
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="App Description" rules="required" v-slot="{ errors }">
<AppInputText title="App Description" :error="errors[0]" :is-last="true">
<textarea class="focus-border-theme input-dark" v-model="app.description" placeholder="Type your app description" type="text" :class="{ 'border-red': errors[0] }"></textarea>
</AppInputText>
</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]" />
</ValidationProvider>
</div>
<div class="card shadow-card text-left">
<FormLabel>Appearance</FormLabel>
<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]" />
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="Theme Color" v-slot="{ errors }">
<AppInputSwitch title="Color Theme">
<input v-model="app.color" type="color" />
</AppInputSwitch>
</ValidationProvider>
<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]" />
<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>
<ValidationProvider tag="div" mode="passive" name="App Logo" v-slot="{ errors }">
<AppInputText title="App Logo (optional)" :error="errors[0]">
<ImageInput v-model="app.logo" :error="errors[0]" />
</AppInputText>
</ValidationProvider>
<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]" />
<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>
<ValidationProvider tag="div" mode="passive" name="App Logo" v-slot="{ errors }">
<AppInputText title="App Logo Horizontal (optional)" :error="errors[0]">
<ImageInput v-model="app.logo_horizontal" :error="errors[0]" />
</AppInputText>
</ValidationProvider>
<FormLabel class="mt-70">Others Information</FormLabel>
<ValidationProvider tag="div" mode="passive" name="App Favicon" v-slot="{ errors }">
<AppInputText title="App Favicon (optional)" :error="errors[0]">
<ImageInput v-model="app.favicon" :error="errors[0]" />
</AppInputText>
</ValidationProvider>
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="App Favicon" v-slot="{ errors }">
<AppInputText title="OG Image (optional)" description="Image that appear when someone shares the content to Facebook or any other social medium. Preferred size is 1200x627" :error="errors[0]">
<ImageInput v-model="app.og_image" :error="errors[0]" />
</AppInputText>
</ValidationProvider>
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="App Favicon" v-slot="{ errors }">
<AppInputText title="App Touch Icon (optional)" description="If user store bookmark on his phone screen, this icon appear in app thumbnail. Preferred size is 156x156" :error="errors[0]" :is-last="true">
<ImageInput v-model="app.touch_icon" :error="errors[0]" />
</AppInputText>
</ValidationProvider>
</div>
<div class="block-wrapper">
<div class="input-wrapper">
<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
>
</div>
<SwitchInput v-model="app.storageLimitation" class="switch" :state="app.storageLimitation" />
</div>
</div>
</div>
<div class="card shadow-card text-left">
<FormLabel>Application</FormLabel>
<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] }"
/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="Contact Email" rules="required" v-slot="{ errors }">
<AppInputText title="Contact Email" :error="errors[0]">
<input class="focus-border-theme input-dark" v-model="app.contactMail" placeholder="Type your contact email" type="email" :class="{ 'border-red': errors[0] }" />
</AppInputText>
</ValidationProvider>
<div class="block-wrapper">
<div class="input-wrapper">
<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
>
</div>
<SwitchInput v-model="app.userRegistration" class="switch" :state="app.userRegistration" />
</div>
</div>
</div>
<ValidationProvider tag="div" mode="passive" name="Google Analytics Code" v-slot="{ errors }">
<AppInputText title="Google Analytics Code (optional)" :error="errors[0]">
<input class="focus-border-theme input-dark" v-model="app.googleAnalytics" placeholder="Paste your Google Analytics Code" type="text" :class="{ 'border-red': errors[0] }" />
</AppInputText>
</ValidationProvider>
<div class="submit-wrapper">
<AuthButton icon="chevron-right" text="Save and Create Admin" :loading="isLoading" :disabled="isLoading" />
</div>
<AppInputSwitch title="Storage Limitation" description="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.">
<SwitchInput v-model="app.storageLimitation" :state="app.storageLimitation" />
</AppInputSwitch>
<ValidationProvider tag="div" mode="passive" name="Default Storage Space" rules="required" v-slot="{ errors }">
<AppInputText v-if="app.storageLimitation" title="Default Storage Space for Accounts" :error="errors[0]">
<input
class="focus-border-theme input-dark"
v-model="app.defaultStorage"
min="1"
max="999999999"
placeholder="Set default storage space in GB"
type="number"
:class="{ 'border-red': errors[0] }"
/>
</AppInputText>
</ValidationProvider>
<AppInputSwitch title="Allow User Registration" description="You can disable public registration for new users. You will still able to create new users in administration panel.">
<SwitchInput v-model="app.userRegistration" class="switch" :state="app.userRegistration" />
</AppInputSwitch>
<AppInputSwitch title="Require Email Verification" description="Turn on, if you want to allow user email verification." :is-last="true">
<SwitchInput v-model="app.userVerification" class="switch" :state="app.userVerification" />
</AppInputSwitch>
</div>
<div class="card shadow-card text-left">
<FormLabel>Subscription</FormLabel>
<ValidationProvider tag="div" mode="passive" name="Contact Email" rules="required" v-slot="{ errors }">
<AppInputText :title="$t('Subscription Type')" description="Choose your preferred subscription system in advance. After installation and any other user registration, you can't change this setting later.">
<SelectInput v-model="app.subscriptionType" :options="$store.getters.subscriptionTypes" :placeholder="$t('Select your subscription type')" />
</AppInputText>
</ValidationProvider>
<InfoBox class="!mb-2">
<p>Any other subscription related settings you will be able set up later in admin panel.</p>
</InfoBox>
</div>
<AuthButton class="w-full justify-center" icon="chevron-right" text="Save and Create Admin" :loading="isLoading" :disabled="isLoading" />
</ValidationObserver>
</AuthContent>
</AuthContentWrapper>
@@ -136,20 +131,23 @@ import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-va
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
import SelectInput from '../../components/Others/Forms/SelectInput'
import SwitchInput from '../../components/Others/Forms/SwitchInput'
import AppInputSwitch from "../../components/Admin/AppInputSwitch"
import ImageInput from '../../components/Others/Forms/ImageInput'
import FormLabel from '../../components/Others/Forms/FormLabel'
import AppInputText from "../../components/Admin/AppInputText"
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: {
AppInputText,
AppInputSwitch,
AuthContentWrapper,
ValidationProvider,
ValidationObserver,
@@ -168,6 +166,8 @@ export default {
return {
isLoading: false,
app: {
color: '#00BC7E',
subscriptionType: undefined,
title: '',
description: '',
logo: undefined,
@@ -180,11 +180,16 @@ export default {
defaultStorage: '5',
userRegistration: 1,
storageLimitation: 1,
userVerification: 0,
},
}
},
methods: {
async appSetupSubmit() {
if (this.$root.$data.config.isSetupWizardDemo) {
this.$router.push({name: 'AdminAccount'})
}
// Validate fields
const isValid = await this.$refs.appSetup.validate()
@@ -197,25 +202,35 @@ export default {
let formData = new FormData()
// Add image to form
formData.append('color', this.app.color)
formData.append('title', this.app.title)
formData.append('description', this.app.description)
formData.append('contactMail', this.app.contactMail)
formData.append('subscriptionType', this.app.subscriptionType)
formData.append('userVerification', Boolean(this.app.userVerification) ? 1 : 0)
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.googleAnalytics)
formData.append('googleAnalytics', this.app.googleAnalytics)
if (this.app.defaultStorage) formData.append('defaultStorage', this.app.defaultStorage)
if (this.app.defaultStorage)
formData.append('defaultStorage', this.app.defaultStorage)
if (this.app.logo) formData.append('logo', this.app.logo)
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.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.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.touch_icon)
formData.append('touch_icon', this.app.touch_icon)
if (this.app.favicon) formData.append('favicon', this.app.favicon)
if (this.app.favicon)
formData.append('favicon', this.app.favicon)
// Send request to get verify account
axios
@@ -242,9 +257,3 @@ export default {
},
}
</script>
<style scoped lang="scss">
@import '../../../sass/vuefilemanager/forms';
@import '../../../sass/vuefilemanager/auth';
@import '../../../sass/vuefilemanager/setup_wizard';
</style>

View File

@@ -1,166 +0,0 @@
<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.">
<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">
<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] }" />
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<FormLabel class="mt-70">Billing Information</FormLabel>
<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]" />
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<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] }" />
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
</div>
<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] }" />
<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] }" />
<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" />
</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'
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
})
},
},
created() {
this.$scrollTop()
},
}
</script>
<style scoped lang="scss">
@import '../../../sass/vuefilemanager/forms';
@import '../../../sass/vuefilemanager/auth';
@import '../../../sass/vuefilemanager/setup_wizard';
</style>

View File

@@ -1,13 +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 database connection to install application database.">
<settings-icon size="40" class="title-icon text-theme mx-auto" />
<AuthContent name="database-credentials" :visible="true" class="!max-w-2xl mt-6 mb-12">
<Headline class="mx-auto max-w-screen-sm !mb-10" title="Setup Wizard" description="Set up your database connection to install application database.">
<settings-icon size="40" class="vue-feather text-theme mx-auto animate-[spin_5s_linear_infinite] mb-3" />
</Headline>
<ValidationObserver @submit.prevent="databaseCredentialsSubmit" ref="verifyPurchaseCode" v-slot="{ invalid }" tag="form" class="form block-form">
<FormLabel>Database Credentials</FormLabel>
<ValidationObserver @submit.prevent="databaseCredentialsSubmit" ref="verifyPurchaseCode" v-slot="{ invalid }" tag="form" class="card shadow-card text-left">
<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
@@ -21,59 +24,47 @@
</ul>
</InfoBox>
<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]"
/>
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="Connection" rules="required" v-slot="{ errors }">
<AppInputText title="Connection" :error="errors[0]">
<SelectInput
v-model="databaseCredentials.connection"
:options="connectionList"
default="mysql"
placeholder="Select your database connection"
:isError="errors[0]"
/>
</AppInputText>
</ValidationProvider>
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="Host" rules="required" v-slot="{ errors }">
<AppInputText title="Host" :error="errors[0]">
<input v-model="databaseCredentials.host" class="focus-border-theme input-dark" placeholder="Type your database host" type="text" :class="{ 'border-red': errors[0] }" />
</AppInputText>
</ValidationProvider>
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="Port" rules="required" v-slot="{ errors }">
<AppInputText title="Port" :error="errors[0]">
<input v-model="databaseCredentials.port" class="focus-border-theme input-dark" placeholder="Type your database port" type="text" :class="{ 'border-red': errors[0] }" />
</AppInputText>
</ValidationProvider>
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="Database Name" rules="required" v-slot="{ errors }">
<AppInputText title="Database Name" :error="errors[0]">
<input v-model="databaseCredentials.name" class="focus-border-theme input-dark" placeholder="Select your database name" type="text" :class="{ 'border-red': errors[0] }" />
</AppInputText>
</ValidationProvider>
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="Database Username" rules="required" v-slot="{ errors }">
<AppInputText title="Database Username" :error="errors[0]">
<input v-model="databaseCredentials.username" class="focus-border-theme input-dark" placeholder="Select your database name" type="text" :class="{ 'border-red': errors[0] }" />
</AppInputText>
</ValidationProvider>
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="Database Password" rules="required" v-slot="{ errors }">
<AppInputText title="Database Password" :error="errors[0]" :is-last="true">
<input v-model="databaseCredentials.password" class="focus-border-theme input-dark" placeholder="Select your database password" type="text" :class="{ 'border-red': errors[0] }" />
</AppInputText>
</ValidationProvider>
<InfoBox v-if="isError" type="error" style="margin-bottom: 10px">
<p>We couldn't establish database connection. Please double check your database credentials.</p>
@@ -81,10 +72,8 @@
<p>Detailed error: {{ errorMessage }}</p>
</InfoBox>
<div class="submit-wrapper">
<AuthButton icon="chevron-right" :text="submitButtonText" :loading="isLoading" :disabled="isLoading" />
</div>
</ValidationObserver>
<AuthButton @click.native="databaseCredentialsSubmit" class="w-full justify-center" icon="chevron-right" :text="submitButtonText" :loading="isLoading" :disabled="isLoading" />
</AuthContent>
</AuthContentWrapper>
</template>
@@ -93,6 +82,7 @@
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
import SelectInput from '../../components/Others/Forms/SelectInput'
import AppInputText from "../../components/Admin/AppInputText"
import FormLabel from '../../components/Others/Forms/FormLabel'
import InfoBox from '../../components/Others/Forms/InfoBox'
import AuthContent from '../../components/Auth/AuthContent'
@@ -109,6 +99,7 @@ export default {
AuthContentWrapper,
ValidationProvider,
ValidationObserver,
AppInputText,
SettingsIcon,
SelectInput,
AuthContent,
@@ -146,6 +137,10 @@ export default {
},
methods: {
async databaseCredentialsSubmit() {
if (this.$root.$data.config.isSetupWizardDemo) {
this.$router.push({name: 'EnvironmentSetup'})
}
// Validate fields
const isValid = await this.$refs.verifyPurchaseCode.validate()
@@ -181,9 +176,3 @@ export default {
},
}
</script>
<style scoped lang="scss">
@import '../../../sass/vuefilemanager/forms';
@import '../../../sass/vuefilemanager/auth';
@import '../../../sass/vuefilemanager/setup_wizard';
</style>

View File

@@ -1,134 +1,104 @@
<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.">
<settings-icon size="40" class="title-icon text-theme mx-auto" />
<AuthContent name="database-credentials" :visible="true" class="!max-w-2xl mt-6 mb-12">
<Headline class="mx-auto max-w-screen-sm !mb-10" title="Setup Wizard" description="Set up your storage driver and email client.">
<settings-icon size="40" class="vue-feather text-theme mx-auto animate-[spin_5s_linear_infinite] mb-3" />
</Headline>
<ValidationObserver @submit.prevent="EnvironmentSetupSubmit" ref="environmentSetup" v-slot="{ invalid }" tag="form" class="form block-form">
<InfoBox>
<p>
If you dont 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>
<ValidationObserver @submit.prevent="EnvironmentSetupSubmit" ref="environmentSetup" v-slot="{ invalid }" tag="form">
<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]" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="card shadow-card text-left">
<FormLabel>Storage Setup</FormLabel>
<div class="storage-additionals" v-if="storage.driver !== 'local'">
<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] }" />
<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] }" />
<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]" />
<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>
</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 />
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<small class="input-help"> Provide your created unique bucket name </small>
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="Storage Service" rules="required" v-slot="{ errors }">
<AppInputText title="Storage Service" :error="errors[0]" :is-last="storage.driver === 'local'">
<SelectInput v-model="storage.driver" :options="storageServiceList" default="local" placeholder="Select your storage service" :isError="errors[0]" />
</AppInputText>
</ValidationProvider>
<InfoBox>
<p>
Later, you can edit these data in your
<b>.env</b> file which is located in app root folder.
</p>
</InfoBox>
</div>
<div v-if="storage.driver !== 'local'">
<FormLabel class="mt-70">Email Setup</FormLabel>
<ValidationProvider tag="div" mode="passive" name="Key" rules="required" v-slot="{ errors }">
<AppInputText title="Key" :error="errors[0]">
<input class="focus-border-theme input-dark" v-model="storage.key" placeholder="Paste your key" type="text" :class="{ 'border-red': errors[0] }" />
</AppInputText>
</ValidationProvider>
<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]" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="Secret" rules="required" v-slot="{ errors }">
<AppInputText title="Secret" :error="errors[0]">
<input class="focus-border-theme input-dark" v-model="storage.secret" placeholder="Paste your secret" type="text" :class="{ 'border-red': errors[0] }" />
</AppInputText>
</ValidationProvider>
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="Region" rules="required" v-slot="{ errors }">
<AppInputText title="Region" description="Select your region where is your bucket/space created." :error="errors[0]">
<SelectInput v-model="storage.region" :options="regionList" :key="storage.driver" placeholder="Select your region" :isError="errors[0]" />
</AppInputText>
</ValidationProvider>
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="Endpoint" rules="required" v-slot="{ errors }">
<AppInputText v-if="storage.driver !== 's3'" title="Endpoint URL" :error="errors[0]">
<input class="focus-border-theme input-dark" v-model="storage.endpoint" placeholder="Type your endpoint" type="text" :class="{ 'border-red': errors[0] }" readonly />
</AppInputText>
</ValidationProvider>
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="Bucket" rules="required" v-slot="{ errors }">
<AppInputText title="Bucket" description="Provide your created unique bucket name" :error="errors[0]" :is-last="true">
<input class="focus-border-theme input-dark" v-model="storage.bucket" placeholder="Type your bucket name" type="text" :class="{ 'border-red': errors[0] }" />
</AppInputText>
</ValidationProvider>
</div>
</div>
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<div class="card shadow-card text-left">
<FormLabel>Email Setup</FormLabel>
<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]" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<ValidationProvider tag="div" mode="passive" name="Mail Driver" rules="required" v-slot="{ errors }">
<AppInputText title="Mail Driver" :error="errors[0]">
<SelectInput v-model="mail.driver" :options="mailDriverList" default="smtp" placeholder="Select your mail driver" :isError="errors[0]" />
</AppInputText>
</ValidationProvider>
<div class="submit-wrapper">
<AuthButton icon="chevron-right" text="Save and Set General Settings" :loading="isLoading" :disabled="isLoading" />
</div>
<ValidationProvider tag="div" mode="passive" name="Mail Host" rules="required" v-slot="{ errors }">
<AppInputText title="Mail Host" :error="errors[0]">
<input class="focus-border-theme input-dark" v-model="mail.host" placeholder="Type your mail host" type="text" :class="{ 'border-red': errors[0] }" />
</AppInputText>
</ValidationProvider>
<ValidationProvider tag="div" mode="passive" name="Mail Port" rules="required" v-slot="{ errors }">
<AppInputText title="Mail Port" :error="errors[0]">
<input class="focus-border-theme input-dark" v-model="mail.port" placeholder="Type your mail port" type="text" :class="{ 'border-red': errors[0] }" />
</AppInputText>
</ValidationProvider>
<ValidationProvider tag="div" mode="passive" name="Mail Username" rules="required" v-slot="{ errors }">
<AppInputText title="Mail Username" :error="errors[0]">
<input class="focus-border-theme input-dark" v-model="mail.username" placeholder="Type your mail username" type="text" :class="{ 'border-red': errors[0] }" />
</AppInputText>
</ValidationProvider>
<ValidationProvider tag="div" mode="passive" name="Mail Password" rules="required" v-slot="{ errors }">
<AppInputText title="Mail Password" :error="errors[0]">
<input class="focus-border-theme input-dark" v-model="mail.password" placeholder="Type your mail password" type="text" :class="{ 'border-red': errors[0] }" />
</AppInputText>
</ValidationProvider>
<ValidationProvider tag="div" mode="passive" name="Mail Encryption" rules="required" v-slot="{ errors }">
<AppInputText title="Mail Encryption" :error="errors[0]" :is-last="true">
<SelectInput v-model="mail.encryption" :options="encryptionList" placeholder="Select your mail encryption" :isError="errors[0]" />
</AppInputText>
</ValidationProvider>
</div>
<AuthButton class="w-full justify-center" icon="chevron-right" text="Save and Set General Settings" :loading="isLoading" :disabled="isLoading" />
</ValidationObserver>
</AuthContent>
</AuthContentWrapper>
</template>
<script>
import AppInputText from "../../components/Admin/AppInputText";
import { ValidationProvider, ValidationObserver } from 'vee-validate/dist/vee-validate.full'
import AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
import SelectInput from '../../components/Others/Forms/SelectInput'
@@ -148,6 +118,7 @@ export default {
AuthContentWrapper,
ValidationProvider,
ValidationObserver,
AppInputText,
SettingsIcon,
SelectInput,
AuthContent,
@@ -467,6 +438,10 @@ export default {
},
methods: {
async EnvironmentSetupSubmit() {
if (this.$root.$data.config.isSetupWizardDemo) {
this.$router.push({name: 'AppSetup'})
}
// Validate fields
const isValid = await this.$refs.environmentSetup.validate()
@@ -499,9 +474,3 @@ export default {
},
}
</script>
<style scoped lang="scss">
@import '../../../sass/vuefilemanager/forms';
@import '../../../sass/vuefilemanager/auth';
@import '../../../sass/vuefilemanager/setup_wizard';
</style>

View File

@@ -1,142 +0,0 @@
<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:"
>
<settings-icon size="40" class="title-icon text-theme mx-auto" />
</Headline>
<div id="loader" v-if="isLoading">
<Spinner></Spinner>
</div>
<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>
</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>
</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>
<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>
</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 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' })
}
})
},
}
</script>
<style scoped lang="scss">
@import '../../../sass/vuefilemanager/forms';
@import '../../../sass/vuefilemanager/auth';
@import '../../../sass/vuefilemanager/setup_wizard';
#loader {
position: relative;
margin-top: 80px;
}
.information-list {
li {
padding: 8px 0;
@include font-size(17);
font-weight: 600;
&:first-child {
padding-top: 0;
}
&:last-child {
padding-bottom: 0;
}
}
}
</style>

View File

@@ -1,37 +1,36 @@
<template>
<AuthContentWrapper ref="auth">
<AuthContentWrapper ref="auth" class="h-screen bg-white">
<!--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.">
<settings-icon size="40" class="title-icon text-theme mx-auto" />
<Headline title="Setup Wizard" description="Please set your purchase code before continue to set up your application.">
<settings-icon size="40" class="vue-feather text-theme mx-auto animate-[spin_5s_linear_infinite] mb-3" />
</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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
<ValidationObserver @submit.prevent="verifyPurchaseCode" ref="verifyPurchaseCode" 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="Purchase Code" rules="required" v-slot="{ errors }">
<input v-model="purchaseCode" placeholder="Paste your purchase code" 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>
<AuthButton icon="chevron-right" text="Verify" :loading="isLoading" :disabled="isLoading" />
<AuthButton icon="chevron-right" text="Verify" class="w-full justify-center md:w-min" :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"> Dont have purchase code? </a>
<p class="block">
<a href="https://help.market.envato.com/hc/en-us/articles/202822600-Where-Is-My-Purchase-Code-" target="_blank" class="text-theme font-bold">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">Dont 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 AuthContentWrapper from '../../components/Auth/AuthContentWrapper'
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 {
@@ -55,6 +54,10 @@ export default {
},
methods: {
async verifyPurchaseCode() {
if (this.$root.$data.config.isSetupWizardDemo) {
this.$router.push({name: 'Database'})
}
// Validate fields
const isValid = await this.$refs.verifyPurchaseCode.validate()
@@ -68,7 +71,7 @@ export default {
.post('/api/setup/purchase-code', {
purchaseCode: this.purchaseCode,
})
.then((response) => {
.then(() => {
// End loading
this.isLoading = false
@@ -81,11 +84,11 @@ export default {
// End loading
this.isLoading = false
if (error.response.status == 400) {
if (error.response.status === 400) {
this.$refs.verifyPurchaseCode.setErrors({
'Purchase Code': ['Purchase code is invalid.'],
})
} else if (error.response.status == 404) {
} 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.'],
})
@@ -99,26 +102,3 @@ export default {
},
}
</script>
<style scoped lang="scss">
@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: $dark_mode_text_primary;
}
}
}
</style>

View File

@@ -1,98 +1,119 @@
<template>
<AuthContentWrapper ref="auth">
<!--Database Credentials-->
<AuthContent name="database-credentials" :visible="true">
<!--Server Check-->
<AuthContent :visible="true" class="!max-w-2xl mt-6 mb-12">
<Headline
class="container mx-auto max-w-screen-sm"
class="mx-auto max-w-screen-sm !mb-10"
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" />
<settings-icon size="40" class="vue-feather text-theme mx-auto animate-[spin_5s_linear_infinite] mb-3" />
</Headline>
<div class="form block-form">
<!--PHP Extension info-->
<FormLabel>Required PHP Extensions</FormLabel>
<InfoBox>
<!--PHP Extension info-->
<div class="card shadow-card">
<FormLabel>
Required PHP Extensions
</FormLabel>
<InfoBox class="!mb-2">
<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>
<div v-if="modules" v-for="(value, module, i) in modules" :key="i" class="py-3 flex items-center justify-between border-b border-dashed border-light dark:border-opacity-5">
<b class="text-sm font-bold">
{{ module }}
</b>
<div class="flex items-center">
<check-icon v-if="value" size="16" class="vue-feather text-theme"/>
<x-icon v-if="!value" size="16" class="vue-feather text-red-600"/>
<!--PHP version and ini check-->
<FormLabel>PHP Version and php.ini</FormLabel>
<InfoBox>
<span class="ml-3 text-sm font-bold" :class="value ? 'text-green-600' : 'text-red-600'">
{{ value ? 'Module Installed' : 'Missing Module' }}
</span>
</div>
</div>
</div>
<!--PHP version and ini check-->
<div class="card shadow-card">
<FormLabel>
PHP Version and php.ini
</FormLabel>
<InfoBox class="!mb-2">
<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>
<div class="py-3 flex items-center justify-between border-b border-dashed border-light dark:border-opacity-5">
<div class="text-left">
<b class="text-sm font-bold block">PHP Version</b>
<small v-if="!phpVersion.acceptable" class="text-xs text-gray-600">
You need PHP version at least {{ phpVersion.minimal }}.
</small>
</div>
<div class="flex items-center">
<check-icon v-if="phpVersion.acceptable" size="16" class="vue-feather text-theme"/>
<x-icon v-if="!phpVersion.acceptable" size="16" class="vue-feather text-red-600" />
<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>
<span class="ml-3 text-sm font-bold" :class="phpVersion.acceptable ? 'text-green-600' : 'text-red-600'">
{{ phpVersion.current }}
</span>
</div>
</div>
<!--API check-->
<FormLabel>API</FormLabel>
<InfoBox>
<div v-for="(values, setting, i) in ini" :key="i" class="py-3 flex items-center justify-between border-b border-dashed border-light dark:border-opacity-5">
<div class="text-left">
<b class="text-sm font-bold block">{{ setting }}</b>
<small v-if="!values.status" class="text-xs text-gray-600">
We recommend set this value at least {{ values.minimal }}.
</small>
</div>
<div class="flex items-center">
<check-icon v-if="values.status" size="16" class="vue-feather text-theme"/>
<x-icon v-if="!values.status" size="16" class="vue-feather text-red-600" />
<span class="ml-3 text-sm font-bold" :class="values.status ? 'text-green-600' : 'text-red-600'">
{{ values.current }}{{ setting !== 'max_execution_time' ? 'M' : '' }}
</span>
</div>
</div>
</div>
<!--API check-->
<div class="card shadow-card">
<FormLabel>
API
</FormLabel>
<InfoBox class="!mb-2">
<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>
<div class="pt-3 flex items-center justify-between">
<div class="text-left">
<b class="text-sm font-bold block">API</b>
<small v-if="isCheckedAPI && !apiRunning" class="text-xs text-gray-600">
We detect, your domain root is not set correctly, please check it.
</small>
</div>
<div v-if="isCheckedAPI" class="flex items-center">
<check-icon v-if="apiRunning" size="16" class="vue-feather text-theme"/>
<x-icon v-if="!apiRunning" size="16" class="vue-feather text-red-600" />
<InfoBox v-if="isError" type="error" style="margin-bottom: 10px">
<span class="ml-3 text-sm font-bold" :class="apiRunning ? 'text-green-600' : 'text-red-600'">
{{ apiRunning ? 'Working correctly' : "Doesn't work" }}
</span>
</div>
<span v-if="!isCheckedAPI" class="ml-3 text-sm font-bold text-gray-600">Checking your API...</span>
</div>
<InfoBox v-if="isError" type="error" class="!mb-2">
<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>
<div class="submit-wrapper">
<AuthButton @click.native="lastCheckBeforeNextPage" icon="chevron-right" text="Awesome, I'm done!" :loading="isLoading" :disabled="isLoading" />
</div>
</div>
<AuthButton @click.native="lastCheckBeforeNextPage" class="w-full justify-center" icon="chevron-right" text="Awesome, I'm done!" :loading="isLoading" :disabled="isLoading" />
</AuthContent>
</AuthContentWrapper>
</template>
@@ -164,7 +185,7 @@ export default {
},
pingAPI() {
axios
.get('/api/setup/ping')
.get('/api/ping')
.then((response) => {
if (response.data === 'pong') {
this.apiRunning = true
@@ -183,71 +204,3 @@ export default {
},
}
</script>
<style scoped lang="scss">
@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-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;
}
}
.status {
display: flex;
align-items: center;
.note {
margin-left: 10px;
@include font-size(12);
font-weight: 600;
color: $text-muted;
}
&.success {
.note {
color: #00bc7e;
}
polyline {
color: #00bc7e;
}
}
&.danger {
.note {
color: #fd397a;
}
line {
color: #fd397a;
}
}
}
.parameter {
@include font-size(14);
}
.help {
@include font-size(12);
color: $text-muted;
display: block;
}
}
</style>

View File

@@ -1,178 +0,0 @@
<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.">
<settings-icon size="40" class="title-icon text-theme mx-auto" />
</Headline>
<ValidationObserver @submit.prevent="stripeCredentialsSubmit" ref="stripeCredentials" v-slot="{ invalid }" tag="form" class="form block-form">
<InfoBox>
<p>
If you dont 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>
<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]" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<FormLabel class="mt-70">Stripe Credentials</FormLabel>
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<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] }" />
<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>
</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 />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<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] }" />
<span class="error-message" v-if="errors[0]">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<InfoBox v-if="isError" type="error" style="margin-bottom: -20px">
<p>{{ errorMessage }}</p>
</InfoBox>
<div class="submit-wrapper">
<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'
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'
},
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()
},
}
</script>
<style scoped lang="scss">
@import '../../../sass/vuefilemanager/forms';
@import '../../../sass/vuefilemanager/auth';
@import '../../../sass/vuefilemanager/setup_wizard';
</style>

View File

@@ -1,195 +0,0 @@
<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.">
<settings-icon size="40" class="title-icon text-theme mx-auto" />
</Headline>
<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>
</InfoBox>
<div class="duplicator">
<div class="plan-item duplicator-item" v-for="(plan, index) in subscriptionPlans" :key="index++">
<x-icon @click="removeRow(plan)" v-if="index !== 1" size="22" class="delete-item"></x-icon>
<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] }" />
<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>
<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] }"
/>
<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] }"
/>
<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>
</div>
<InfoBox v-if="isError" type="error" style="margin-top: 40px">
<p>{{ errorMessage }}</p>
</InfoBox>
<div class="submit-wrapper">
<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 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,
},
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',
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';
</style>

View File

@@ -1,149 +0,0 @@
<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:"
>
<settings-icon size="40" class="title-icon text-theme mx-auto" />
</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" />
<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">
<span>Set Up Billing and Plans With Stripe</span>
<chevron-right-icon size="22" class="icon"></chevron-right-icon>
</router-link>
</router-link>
</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>
</p>
</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 { 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()
},
}
</script>
<style scoped lang="scss">
@import '../../../sass/vuefilemanager/auth';
@import '../../../sass/vuefilemanager/setup_wizard';
.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-logo {
margin-bottom: 30px;
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;
}
}
}
.skip-subscription-setup {
border: none !important;
}
.auth-form input {
min-width: 380px;
}
</style>

View File

@@ -1,101 +0,0 @@
.content-headline {
max-width: 630px;
margin-left: auto;
margin-right: auto;
}
.auth-form {
input {
min-width: initial;
}
}
.duplicator {
.duplicator-add-button {
width: 100%;
}
.duplicator-item {
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.12);
border-radius: 8px;
background: white;
padding: 25px;
margin: 0 -25px 32px;
position: relative;
.duplicator-title {
@include font-size(18);
margin-bottom: 20px;
display: block;
font-weight: 700;
}
.delete-item {
position: absolute;
top: 15px;
right: 15px;
cursor: pointer;
&:hover {
line {
stroke: $theme;
}
}
}
input,
textarea {
box-shadow: none;
background: #FAFAFA;
}
}
}
.form {
max-width: 580px;
text-align: left;
}
.submit-wrapper {
text-align: right;
.button {
margin: 58px 0 50px 0;
width: 100%;
}
}
.title-icon {
margin-bottom: 10px;
animation: spinner 5s linear infinite;
circle, path {
color: inherit;
}
}
@keyframes spinner {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.dark {
.duplicator {
.duplicator-item {
background: $dark_mode_foreground;
input,
textarea {
background: $dark_mode_background;
}
}
}
}

View File

@@ -3,19 +3,28 @@
use VueFileManager\Subscription\Domain\Transactions\Models\Transaction;
use VueFileManager\Subscription\Domain\Subscriptions\Models\Subscription;
// Subscription
$plan = Plan::where('status', 'active')->where('type', 'metered');
try {
// Subscription
$isEmptySubscriptions = Subscription::count() === 0;
$isEmptyTransactions = Transaction::count() === 0;
$isEmptyPlans = Plan::count() === 0;
$plan = Plan::where('status', 'active')
->where('type', 'metered');
$isEmptyPlans = Plan::count() === 0;
$isEmptyTransactions = Transaction::count() === 0;
$isEmptySubscriptions = Subscription::count() === 0;
// User
$isUser = auth()->check();
$user = Auth::user();
// User
$isUser = auth()->check();
$user = Auth::user();
// Default user settings
$defaultEmoji = $isUser ? $user->settings->emoji_type : 'twemoji';
$defaultThemeMode = $isUser ? $user->settings->theme_mode : 'system';
} catch (PDOException $e) {
[$isUser, $isEmptyPlans, $isEmptyTransactions, $isEmptySubscriptions] = false;
$defaultEmoji = $isUser ? $user->settings->emoji_type : 'twemoji';
$defaultThemeMode = $isUser ? $user->settings->theme_mode : 'system';
$plan = null;
$defaultEmoji = 'twemoji';
$defaultThemeMode = 'system';
}
@endphp
<!DOCTYPE html>
@@ -55,7 +64,7 @@
@include('vuefilemanager.others.color-template')
</head>
<body class="{{ is_dev() ? 'debug-screens' : '' }}">
<body class="bg-light-background {{ is_dev() ? 'debug-screens' : '' }}">
<div id="app"></div>
@@ -66,6 +75,7 @@
host: '{{ url('/') }}',
api: '{{ url('/api') }}',
locale: '{{ app()->getLocale() }}',
isSetupWizardDemo: '{{ env('IS_SETUP_WIZARD_DEMO', 0) }}',
app_color: '{{ $settings->app_color ?? '#00BC7E' }}',
app_logo: '{{ $settings->app_logo ?? null }}',
@@ -83,7 +93,7 @@
uploadLimitFormatted: '{{ isset($settings->upload_limit) ? format_megabytes($settings->upload_limit) : null }}',
chunkSize: {{ format_bytes(config('vuefilemanager.chunk_size')) }},
isAuthenticated: {{ auth()->check() ? 1 : 0 }},
isAuthenticated: {{ $isUser ? 1 : 0 }},
isSaaS: {{ $settings && $settings->license === 'Extended' ? 1 : 0 }},
isDev: {{ is_dev() ? 1 : 0 }},
@@ -105,8 +115,8 @@
// Metered
allowed_registration_bonus: {{ $settings->allowed_registration_bonus ?? 0 }},
registration_bonus_amount: {{ $settings->registration_bonus_amount ?? 0 }},
isCreatedMeteredPlan: {{ $plan->exists() ? 1 : 0 }},
meteredPlanId: '{{ $plan->exists() ? $plan->first()->id : null }}',
isCreatedMeteredPlan: {{ $plan && $plan->exists() ? 1 : 0 }},
meteredPlanId: '{{ $plan && $plan->exists() ? $plan->first()->id : null }}',
// Payments
allowed_payments: {{ $settings->allowed_payments ?? 0 }},

View File

@@ -1,5 +1,6 @@
<?php
use Domain\SetupWizard\Controllers\PingAPIController;
use Domain\Zip\Controllers\ZipController;
use Domain\Pages\Controllers\PagesController;
use Domain\Sharing\Controllers\ShareController;
@@ -27,6 +28,9 @@ use Domain\Homepage\Controllers\SendContactMessageController;
use Domain\Sharing\Controllers\GetShareLinkViaQrCodeController;
use App\Users\Controllers\Authentication\RegisterUserController;
// Ping Pong
Route::get('/ping', PingAPIController::class);
// Pages
Route::apiResource('/page', PagesController::class);

View File

@@ -1,24 +1,16 @@
<?php
use Domain\SetupWizard\Controllers\PingAPIController;
use Domain\SetupWizard\Controllers\StorePlansController;
use Domain\SetupWizard\Controllers\StoreBillingsController;
use Domain\SetupWizard\Controllers\StoreAppSettingsController;
use Domain\SetupWizard\Controllers\CreateAdminAccountController;
use Domain\SetupWizard\Controllers\VerifyPurchaseCodeController;
use Domain\SetupWizard\Controllers\StoreDatabaseCredentialsController;
use Domain\SetupWizard\Controllers\StoreEnvironmentSettingsController;
use Domain\SetupWizard\Controllers\StoreSubscriptionServiceCredentialsController;
Route::group(['prefix' => 'api/setup'], function () {
Route::post('/stripe-credentials', StoreSubscriptionServiceCredentialsController::class);
Route::post('/environment-setup', StoreEnvironmentSettingsController::class);
Route::post('/database', StoreDatabaseCredentialsController::class);
Route::post('/purchase-code', VerifyPurchaseCodeController::class);
Route::post('/stripe-billings', StoreBillingsController::class);
Route::post('/app-setup', StoreAppSettingsController::class);
Route::post('/stripe-plans', StorePlansController::class);
Route::get('/ping', PingAPIController::class);
});
Route::post('/admin-setup', CreateAdminAccountController::class)

View File

@@ -1,11 +1,13 @@
<?php
namespace Domain\Homepage\Controllers;
use DB;
use Domain\Pages\Models\Page;
use Illuminate\Contracts\View\View;
use Doctrine\DBAL\Driver\PDOException;
use Illuminate\Contracts\View\Factory;
use Illuminate\Contracts\Foundation\Application;
use PDOException;
class IndexController
{
@@ -16,7 +18,7 @@ class IndexController
{
try {
// Try to connect to database
\DB::getPdo();
DB::getPdo();
// Get setup status
$setup_status = get_setup_status();
@@ -33,7 +35,7 @@ class IndexController
$upload_max_filesize = 128;
$post_max_size = 128;
$memory_limit = 512;
$max_execution_time = 3600;
$max_execution_time = 600;
$php_version = '8.0';
$status_check = [
@@ -47,6 +49,7 @@ class IndexController
'ctype' => extension_loaded('ctype'),
'json' => extension_loaded('json'),
'exif' => extension_loaded('exif'),
'intl' => extension_loaded('intl'),
'pdo' => extension_loaded('pdo'),
'xml' => extension_loaded('xml'),
'gd' => extension_loaded('gd'),

View File

@@ -16,6 +16,18 @@ class StoreAppSettingsController extends Controller
StoreAppSetupRequest $request
): Response {
collect([
[
'name' => 'subscription_type',
'value' => $request->input('subscriptionType'),
],
[
'name' => 'user_verification',
'value' => $request->input('userVerification'),
],
[
'name' => 'app_color',
'value' => $request->input('color'),
],
[
'name' => 'app_title',
'value' => $request->input('title'),

View File

@@ -1,64 +0,0 @@
<?php
namespace Domain\SetupWizard\Controllers;
use Artisan;
use Illuminate\Http\Response;
use Domain\Settings\Models\Setting;
use App\Http\Controllers\Controller;
use Domain\SetupWizard\Requests\StoreStripeBillingRequest;
class StoreBillingsController extends Controller
{
/**
* Store Stripe billings
*/
public function __invoke(
StoreStripeBillingRequest $request
): Response {
collect([
[
'name' => 'billing_phone_number',
'value' => $request->input('billing_phone_number'),
],
[
'name' => 'billing_postal_code',
'value' => $request->input('billing_postal_code'),
],
[
'name' => 'billing_vat_number',
'value' => $request->input('billing_vat_number'),
],
[
'name' => 'billing_address',
'value' => $request->input('billing_address'),
],
[
'name' => 'billing_country',
'value' => $request->input('billing_country'),
],
[
'name' => 'billing_state',
'value' => $request->input('billing_state'),
],
[
'name' => 'billing_city',
'value' => $request->input('billing_city'),
],
[
'name' => 'billing_name',
'value' => $request->input('billing_name'),
],
])->each(function ($col) {
Setting::forceCreate([
'name' => $col['name'],
'value' => $col['value'],
]);
});
if (! app()->runningUnitTests()) {
Artisan::call('config:cache');
}
return response('Done', 204);
}
}

View File

@@ -1,22 +0,0 @@
<?php
namespace Domain\SetupWizard\Controllers;
use Illuminate\Http\Response;
use App\Http\Controllers\Controller;
use Domain\SetupWizard\Requests\StoreStripePlansRequest;
/**
* Create Stripe subscription plan
*/
class StorePlansController extends Controller
{
public function __invoke(
StoreStripePlansRequest $request
): Response {
foreach ($request->input('plans') as $plan) {
$this->stripe->createPlan($plan);
}
return response('Done', 204);
}
}

View File

@@ -1,69 +0,0 @@
<?php
namespace Domain\SetupWizard\Controllers;
use Stripe;
use Artisan;
use Illuminate\Http\Response;
use Domain\Settings\Models\Setting;
use App\Http\Controllers\Controller;
use Cartalyst\Stripe\Exception\UnauthorizedException;
use Symfony\Component\HttpKernel\Exception\HttpException;
use Domain\SetupWizard\Requests\StoreStripeCredentialsRequest;
class StoreSubscriptionServiceCredentialsController extends Controller
{
/**
* Store and test stripe credentials
*/
public function __invoke(
StoreStripeCredentialsRequest $request
): Response {
if (! app()->runningUnitTests()) {
// Create stripe instance
$stripe = Stripe::make($request->input('secret'), '2020-03-02');
try {
// Try to get stripe account details
$stripe->account()->details();
} catch (UnauthorizedException $e) {
throw new HttpException(401, $e->getMessage());
}
}
// Set settings
collect([
[
'name' => 'stripe_currency',
'value' => $request->input('currency'),
],
[
'name' => 'payments_configured',
'value' => 1,
],
[
'name' => 'payments_active',
'value' => 1,
],
])->each(function ($col) {
Setting::forceCreate([
'name' => $col['name'],
'value' => $col['value'],
]);
});
if (! app()->runningUnitTests()) {
// Set stripe credentials to .env
setEnvironmentValue([
'CASHIER_CURRENCY' => $request->input('currency'),
'STRIPE_KEY' => $request->input('key'),
'STRIPE_SECRET' => $request->input('secret'),
'STRIPE_WEBHOOK_SECRET' => $request->input('webhookSecret'),
]);
// Clear cache
Artisan::call('config:cache');
}
return response('Done', 204);
}
}

View File

@@ -13,7 +13,6 @@ class SetupServiceTest extends TestCase
public function it_create_system_folders()
{
// folders are created in TestCase
collect(['avatars', 'chunks', 'system', 'files', 'temp', 'zip'])
->each(function ($directory) {
Storage::disk('local')->assertExists($directory);

View File

@@ -1,4 +1,5 @@
<?php
namespace Tests\Domain\SetupWizard;
use Tests\TestCase;
@@ -10,14 +11,6 @@ use Illuminate\Support\Facades\Storage;
class SetupWizardTest extends TestCase
{
/**
* CAVEAT:
*
* The route '/api/setup/stripe-plans' which is part of setup wizard is moved to
* SubscriptionTest.php to group all live API test. For more info how to test
* subscription integration in VueFileManager platform visit https://laravel.com/docs/8.x/billing#testing
*/
/**
* @test
*/
@@ -66,89 +59,6 @@ class SetupWizardTest extends TestCase
]);
}
/**
* @test
*/
public function it_store_stripe_credentials()
{
$this->postJson('/api/setup/stripe-credentials', [
'currency' => 'EUR',
'key' => '123456789',
'secret' => '123456789',
'webhookSecret' => '123456789',
])->assertStatus(204);
$this->assertDatabaseHas('settings', [
'name' => 'stripe_currency',
'value' => 'EUR',
]);
$this->assertDatabaseHas('settings', [
'name' => 'payments_configured',
'value' => 1,
]);
$this->assertDatabaseHas('settings', [
'name' => 'payments_active',
'value' => 1,
]);
}
/**
* @test
*/
public function it_store_stripe_billings()
{
$payload = collect([
'billing_phone_number' => '+421123456789',
'billing_postal_code' => '04001',
'billing_vat_number' => 'SK20042134234',
'billing_address' => 'Does 20',
'billing_country' => 'Doeland',
'billing_state' => 'Doeslandia',
'billing_city' => 'Does',
'billing_name' => 'John Doe Ltd.',
]);
$this->postJson('/api/setup/stripe-billings', $payload->toArray())
->assertStatus(204);
$payload
->each(function ($value, $key) {
$this->assertDatabaseHas('settings', [
'name' => $key,
'value' => $value,
]);
});
}
/**
*
*/
public function it_store_stripe_plans()
{
}
/**
* @test
*/
public function it_store_environment()
{
$this->postJson('/api/setup/environment-setup', [
'storage' => [
'driver' => 'local',
],
'mail' => [
'driver' => 'smtp',
'host' => 'smtp.email.com',
'port' => '25',
'username' => 'john@doe.com',
'password' => 'secret',
'encryption' => 'tls',
],
])->assertStatus(204);
}
/**
* @test
*/
@@ -157,10 +67,13 @@ class SetupWizardTest extends TestCase
Setting::all()->each->delete();
$this->postJson('/api/setup/app-setup', [
'color' => '#00BC7E',
'title' => 'VueFileManager',
'description' => 'The best file manager on the internet',
'googleAnalytics' => 'UA-12345678-1',
'contactMail' => 'john@doe.com',
'subscriptionType' => 'metered',
'userVerification' => 1,
'userRegistration' => 1,
'storageLimitation' => 1,
'defaultStorage' => 10,
@@ -169,30 +82,39 @@ class SetupWizardTest extends TestCase
'favicon' => UploadedFile::fake()->image('fake-favicon.jpg'),
])->assertStatus(204);
$this->assertDatabaseHas('settings', [
'name' => 'app_title',
'value' => 'VueFileManager',
]);
$this->assertDatabaseHas('settings', [
'name' => 'app_description',
'value' => 'The best file manager on the internet',
]);
$this->assertDatabaseHas('settings', [
'name' => 'google_analytics',
'value' => 'UA-12345678-1',
]);
$this->assertDatabaseHas('settings', [
'name' => 'contact_email',
'value' => 'john@doe.com',
]);
$this->assertDatabaseHas('settings', [
'name' => 'default_max_storage_amount',
'value' => '10',
]);
$this
->assertDatabaseHas('settings', [
'name' => 'subscription_type',
'value' => 'metered',
])
->assertDatabaseHas('settings', [
'name' => 'user_verification',
'value' => 1,
])
->assertDatabaseHas('settings', [
'name' => 'app_color',
'value' => '#00BC7E',
])
->assertDatabaseHas('settings', [
'name' => 'app_title',
'value' => 'VueFileManager',
])
->assertDatabaseHas('settings', [
'name' => 'app_description',
'value' => 'The best file manager on the internet',
])
->assertDatabaseHas('settings', [
'name' => 'google_analytics',
'value' => 'UA-12345678-1',
])
->assertDatabaseHas('settings', [
'name' => 'contact_email',
'value' => 'john@doe.com',
])
->assertDatabaseHas('settings', [
'name' => 'default_max_storage_amount',
'value' => '10',
]);
collect(['app_logo', 'app_logo_horizontal', 'app_favicon'])
->each(function ($file) {
@@ -279,9 +201,8 @@ class SetupWizardTest extends TestCase
collect(config('vuefilemanager.avatar_sizes'))
->each(
fn ($size) =>
Storage::disk('local')
->assertExists("avatars/{$size['name']}-{$avatar}")
fn($size) => Storage::disk('local')
->assertExists("avatars/{$size['name']}-{$avatar}")
);
}