aboutsummaryrefslogtreecommitdiff
path: root/src/site
diff options
context:
space:
mode:
Diffstat (limited to 'src/site')
-rw-r--r--src/site/components/navbar/Navbar.vue10
-rw-r--r--src/site/layouts/default.vue66
-rw-r--r--src/site/middleware/admin.js4
-rw-r--r--src/site/middleware/auth.js2
-rw-r--r--src/site/pages/dashboard/index.vue124
-rw-r--r--src/site/pages/index.vue10
-rw-r--r--src/site/pages/login.vue39
-rw-r--r--src/site/pages/register.vue10
-rw-r--r--src/site/plugins/axios.js9
-rw-r--r--src/site/store/alert.js26
-rw-r--r--src/site/store/auth.js61
-rw-r--r--src/site/store/config.js19
-rw-r--r--src/site/store/images.js56
-rw-r--r--src/site/store/index.js62
14 files changed, 317 insertions, 181 deletions
diff --git a/src/site/components/navbar/Navbar.vue b/src/site/components/navbar/Navbar.vue
index 47f90cb..aa4a672 100644
--- a/src/site/components/navbar/Navbar.vue
+++ b/src/site/components/navbar/Navbar.vue
@@ -65,6 +65,8 @@
</template>
<script>
+import { mapState, mapGetters } from 'vuex';
+
export default {
props: {
isWhite: {
@@ -76,12 +78,8 @@ export default {
return { hamburger: false };
},
computed: {
- loggedIn() {
- return this.$store.state.loggedIn;
- },
- config() {
- return this.$store.state.config;
- }
+ ...mapGetters({ loggedIn: 'auth/isLoggedIn' }),
+ ...mapState(['config'])
},
methods: {
logOut() {
diff --git a/src/site/layouts/default.vue b/src/site/layouts/default.vue
index 61a257e..08d733f 100644
--- a/src/site/layouts/default.vue
+++ b/src/site/layouts/default.vue
@@ -12,22 +12,18 @@
<script>
import Navbar from '~/components/navbar/Navbar.vue';
import Footer from '~/components/footer/Footer';
+import { mapState } from 'vuex';
+
export default {
components: {
- Navbar,
+ Navbar,
Footer
},
- computed: {
- config() {
- return this.$store.state.config;
- },
- alert() {
- return this.$store.state.alert;
- }
- },
+ computed: mapState(['config', 'alert']),
watch: {
- alert() {
- if (!this.alert) return;
+ 'alert.text'() {
+ console.log('aaaaaaaa');
+ if (!this.alert.text) return;
this.$buefy.toast.open({
duration: 3500,
@@ -36,34 +32,40 @@ export default {
type: this.alert.error ? 'is-danger' : 'is-success'
});
- setTimeout(() => {
- this.$store.dispatch('alert', null);
- }, 3500);
+ this.$store.dispatch('alert/clear', null);
}
},
mounted() {
- console.log(`%c lolisafe %c v${this.config.version} %c`, 'background:#35495e ; padding: 1px; border-radius: 3px 0 0 3px; color: #fff', 'background:#ff015b; padding: 1px; border-radius: 0 3px 3px 0; color: #fff', 'background:transparent');
+ console.log(
+ `%c lolisafe %c v${this.config.version} %c`,
+ 'background:#35495e ; padding: 1px; border-radius: 3px 0 0 3px; color: #fff',
+ 'background:#ff015b; padding: 1px; border-radius: 0 3px 3px 0; color: #fff',
+ 'background:transparent'
+ );
}
};
</script>
+
<style lang="scss">
- html { overflow: hidden !important; }
- .is-fullheight {
- min-height: 100vh !important;
- height: max-content;
- }
- .nuxt-app > .section {
- min-height: auto !important;
- height: auto !important;
- }
- @import "~/assets/styles/style.scss";
- @import "~/assets/styles/icons.min.css";
+html {
+ overflow: hidden !important;
+}
+.is-fullheight {
+ min-height: 100vh !important;
+ height: max-content;
+}
+.nuxt-app > .section {
+ min-height: auto !important;
+ height: auto !important;
+}
+@import '~/assets/styles/style.scss';
+@import '~/assets/styles/icons.min.css';
</style>
<style lang="scss" scoped>
- .default-body {
- align-items: baseline !important;
- }
- .scroll-area {
- height: 100vh;
- }
+.default-body {
+ align-items: baseline !important;
+}
+.scroll-area {
+ height: 100vh;
+}
</style>
diff --git a/src/site/middleware/admin.js b/src/site/middleware/admin.js
index fcac9c6..5c09220 100644
--- a/src/site/middleware/admin.js
+++ b/src/site/middleware/admin.js
@@ -1,5 +1,5 @@
export default function({ store, redirect }) {
// If the user is not authenticated
- if (!store.state.user) return redirect('/login');
- if (!store.state.user.isAdmin) return redirect('/dashboard');
+ if (!store.state.auth.user) return redirect('/login');
+ if (!store.state.auth.user.isAdmin) return redirect('/dashboard');
}
diff --git a/src/site/middleware/auth.js b/src/site/middleware/auth.js
index 58a372e..c3f339c 100644
--- a/src/site/middleware/auth.js
+++ b/src/site/middleware/auth.js
@@ -1,6 +1,6 @@
export default function({ store, redirect }) {
// If the user is not authenticated
- if (!store.state.loggedIn) {
+ if (!store.state.auth.loggedIn) {
return redirect('/login');
}
}
diff --git a/src/site/pages/dashboard/index.vue b/src/site/pages/dashboard/index.vue
index 0eb9532..6c1b99b 100644
--- a/src/site/pages/dashboard/index.vue
+++ b/src/site/pages/dashboard/index.vue
@@ -6,27 +6,55 @@
<Sidebar />
</div>
<div class="column">
- <h2 class="subtitle">Your uploaded files</h2>
+ <nav class="level">
+ <div class="level-left">
+ <div class="level-item">
+ <h2 class="subtitle">Your uploaded files</h2>
+ </div>
+ </div>
+ <div class="level-right">
+ <div class="level-item">
+ <b-field>
+ <b-input
+ placeholder="Search"
+ type="search"/>
+ <p class="control">
+ <button
+ outlined
+ class="button is-primary">
+ Search
+ </button>
+ </p>
+ </b-field>
+ </div>
+ </div>
+ </nav>
<hr>
- <Grid v-if="count"
- :files="files"
- :enableSearch="false"
- class="grid" />
+ <b-loading :active="images.isLoading" />
- <b-pagination
- v-if="count > perPage"
- :total="count"
- :per-page="perPage"
- :current.sync="current"
- class="pagination"
- icon-prev="icon-interface-arrow-left"
- icon-next="icon-interface-arrow-right"
- icon-pack="icon"
- aria-next-label="Next page"
- aria-previous-label="Previous page"
- aria-page-label="Page"
- aria-current-label="Current page" />
+ <Grid v-if="totalFiles"
+ :files="images.files"
+ :enableSearch="false"
+ class="grid">
+ <template v-slot:pagination>
+ <b-pagination
+ v-if="shouldPaginate"
+ :total="totalFiles"
+ :per-page="limit"
+ :current.sync="current"
+ range-before="2"
+ range-after="2"
+ class="pagination-slot"
+ icon-prev="icon-interface-arrow-left"
+ icon-next="icon-interface-arrow-right"
+ icon-pack="icon"
+ aria-next-label="Next page"
+ aria-previous-label="Previous page"
+ aria-page-label="Page"
+ aria-current-label="Current page" />
+ </template>
+ </Grid>
</div>
</div>
</div>
@@ -34,6 +62,8 @@
</template>
<script>
+import { mapState, mapGetters, mapActions } from 'vuex';
+
import Sidebar from '~/components/sidebar/Sidebar.vue';
import Grid from '~/components/grid/Grid.vue';
@@ -42,44 +72,34 @@ export default {
Sidebar,
Grid
},
- middleware: 'auth',
+ middleware: ['auth', ({ store }) => {
+ store.dispatch('images/fetch');
+ }],
data() {
return {
- files: [],
- count: 0,
- current: 1,
- perPage: 30
+ current: 1
};
},
+ computed: {
+ ...mapGetters({
+ totalFiles: 'images/getTotalFiles',
+ shouldPaginate: 'images/shouldPaginate',
+ limit: 'images/getLimit'
+ }),
+ ...mapState(['images'])
+ },
metaInfo() {
return { title: 'Uploads' };
},
watch: {
- current: 'getFiles'
- },
- async asyncData({ $axios, route }) {
- const perPage = 30;
- const current = 1; // current page
-
- try {
- const response = await $axios.$get(`files`, { params: { page: current, limit: perPage }});
- return {
- files: response.files || [],
- count: response.count || 0,
- current,
- perPage
- };
- } catch (error) {
- console.error(error);
- return { files: [] };
- }
+ current: 'fetchPaginate'
},
methods: {
- async getFiles() {
- // TODO: Cache a few pages once fetched
- const response = await this.$axios.$get(`files`, { params: { page: this.current, limit: this.perPage }});
- this.files = response.files;
- this.count = response.count;
+ ...mapActions({
+ fetch: 'images/fetch'
+ }),
+ fetchPaginate() {
+ this.fetch(this.current)
}
}
};
@@ -89,4 +109,14 @@ export default {
div.grid {
margin-bottom: 1rem;
}
-</style> \ No newline at end of file
+
+ .pagination-slot {
+ padding: 1rem 0;
+ }
+</style>
+
+<style lang="scss">
+ .pagination-slot > .pagination-previous, .pagination-slot > .pagination-next {
+ display: none !important;
+ }
+</style>
diff --git a/src/site/pages/index.vue b/src/site/pages/index.vue
index 707ae67..bb35be3 100644
--- a/src/site/pages/index.vue
+++ b/src/site/pages/index.vue
@@ -28,6 +28,8 @@
</div>
</template>
<script>
+import { mapState, mapGetters } from 'vuex';
+
import Logo from '~/components/logo/Logo.vue';
import Uploader from '~/components/uploader/Uploader.vue';
import Links from '~/components/home/links/Links.vue';
@@ -43,12 +45,8 @@ export default {
return { albums: [] };
},
computed: {
- loggedIn() {
- return this.$store.state.loggedIn;
- },
- config() {
- return this.$store.state.config;
- }
+ ...mapGetters({ loggedIn: 'auth/isLoggedIn' }),
+ ...mapState(['config'])
}
};
</script>
diff --git a/src/site/pages/login.vue b/src/site/pages/login.vue
index 514cbc5..3c43755 100644
--- a/src/site/pages/login.vue
+++ b/src/site/pages/login.vue
@@ -63,6 +63,8 @@
</template>
<script>
+import { mapState } from 'vuex';
+
export default {
name: 'Login',
data() {
@@ -74,40 +76,31 @@ export default {
isLoading: false
};
},
- computed: {
- config() {
- return this.$store.state.config;
- }
- },
+ computed: mapState(['config', 'auth']),
metaInfo() {
return { title: 'Login' };
},
+ created() {
+ if (this.auth.loggedIn) {
+ this.redirect();
+ }
+ },
methods: {
async login() {
- if (this.isLoading) return;
- if (!this.username || !this.password) {
- this.$store.dispatch('alert', {
+ if (this.auth.isLoading) return;
+
+ const { username, password } = this;
+ if (!username || !password) {
+ this.$store.dispatch('alert/set', {
text: 'Please fill both fields before attempting to log in.',
error: true
});
return;
}
- this.isLoading = true;
-
- try {
- const data = await this.$axios.$post(`auth/login`, {
- username: this.username,
- password: this.password
- });
- this.$axios.setToken(data.token, 'Bearer');
- document.cookie = `token=${encodeURIComponent(data.token)}`;
- this.$store.dispatch('login', { token: data.token, user: data.user });
+ await this.$store.dispatch('auth/login', { username, password });
+ if (this.auth.loggedIn) {
this.redirect();
- } catch (error) {
- //
- } finally {
- this.isLoading = false;
}
},
/*
@@ -126,7 +119,7 @@ export default {
});
},*/
redirect() {
- this.$store.commit('loggedIn', true);
+ console.log('redirect');
if (typeof this.$route.query.redirect !== 'undefined') {
this.$router.push(this.$route.query.redirect);
return;
diff --git a/src/site/pages/register.vue b/src/site/pages/register.vue
index c102abd..92eb35a 100644
--- a/src/site/pages/register.vue
+++ b/src/site/pages/register.vue
@@ -42,6 +42,8 @@
</template>
<script>
+import { mapState } from 'vuex';
+
export default {
name: 'Register',
data() {
@@ -52,11 +54,7 @@ export default {
isLoading: false
};
},
- computed: {
- config() {
- return this.$store.state.config;
- }
- },
+ computed: mapState(['config', 'auth']),
metaInfo() {
return { title: 'Register' };
},
@@ -72,7 +70,7 @@ export default {
}
if (this.password !== this.rePassword) {
this.$store.dispatch('alert', {
- text: 'Passwords don\'t match',
+ text: "Passwords don't match",
error: true
});
return;
diff --git a/src/site/plugins/axios.js b/src/site/plugins/axios.js
index 843a258..cff149c 100644
--- a/src/site/plugins/axios.js
+++ b/src/site/plugins/axios.js
@@ -1,21 +1,22 @@
export default function({ $axios, store }) {
$axios.setHeader('accept', 'application/vnd.lolisafe.json');
+
$axios.onRequest(config => {
- if (store.state.token) {
- config.headers.common['Authorization'] = `bearer ${store.state.token}`;
+ if (store.state.auth.token) {
+ config.headers.common['Authorization'] = `bearer ${store.state.auth.token}`;
}
});
$axios.onError(error => {
if (process.env.development) console.error('[AXIOS Error]', error);
if (process.browser) {
- store.dispatch('alert', {
+ store.dispatch('alert/set', {
text: error.response.data.message,
error: true
});
if (error.response.data.message.indexOf('Token expired') !== -1) {
- store.dispatch('logout');
+ store.dispatch('auth/logout');
}
}
});
diff --git a/src/site/store/alert.js b/src/site/store/alert.js
new file mode 100644
index 0000000..78c0eaf
--- /dev/null
+++ b/src/site/store/alert.js
@@ -0,0 +1,26 @@
+/* eslint-disable no-shadow */
+const getDefaultState = () => ({
+ text: null,
+ error: false
+});
+
+export const state = getDefaultState;
+
+export const actions = {
+ set({ commit }, data) {
+ commit('set', data);
+ },
+ clear({ commit }) {
+ commit('clear');
+ }
+};
+
+export const mutations = {
+ set(state, { text, error }) {
+ state.text = text;
+ state.error = error;
+ },
+ clear(state) {
+ Object.assign(state, getDefaultState());
+ }
+};
diff --git a/src/site/store/auth.js b/src/site/store/auth.js
new file mode 100644
index 0000000..a62a6ec
--- /dev/null
+++ b/src/site/store/auth.js
@@ -0,0 +1,61 @@
+/* eslint-disable no-shadow */
+// only used so I could keep the convention of naming the first param as "state" in mutations
+const getDefaultState = () => ({
+ loggedIn: false,
+ isLoading: false,
+ user: null,
+ token: null
+});
+
+export const state = getDefaultState;
+
+export const getters = {
+ isLoggedIn: state => state.loggedIn
+};
+
+export const actions = {
+ async verify({ commit, dispatch }) {
+ try {
+ const response = await this.$axios.$get('verify');
+ commit('loginSuccess', response);
+ } catch (e) {
+ dispatch('alert/set', { text: e.message, error: true }, { root: true });
+ }
+ },
+ async login({ commit, dispatch }, { username, password }) {
+ commit('loginRequest');
+
+ try {
+ const data = await this.$axios.$post(`auth/login`, { username, password });
+ this.$axios.setToken(data.token, 'Bearer');
+
+ commit('setToken', data.token);
+ commit('loginSuccess', { token: data.token, user: data.user });
+ } catch (e) {
+ dispatch('alert/set', { text: e.message, error: true }, { root: true });
+ }
+ },
+ logout({ commit }) {
+ commit('logout');
+ }
+};
+
+export const mutations = {
+ setToken(state, token) {
+ state.token = token;
+ },
+ loginRequest(state) {
+ state.isLoading = true;
+ },
+ loginSuccess(state, { user }) {
+ this.$cookies.set('token', state.token);
+ state.user = user;
+ state.loggedIn = true;
+ state.isLoading = false;
+ },
+ logout(state) {
+ this.$cookies.remove('token');
+ // reset state to default
+ Object.assign(state, getDefaultState());
+ }
+};
diff --git a/src/site/store/config.js b/src/site/store/config.js
new file mode 100644
index 0000000..6202f84
--- /dev/null
+++ b/src/site/store/config.js
@@ -0,0 +1,19 @@
+/* eslint-disable no-shadow */
+export const state = () => ({
+ development: true,
+ version: '4.0.0',
+ URL: 'http://localhost:8080',
+ baseURL: 'http://localhost:8080/api',
+ serviceName: '',
+ maxFileSize: 100,
+ chunkSize: 90,
+ maxLinksPerAlbum: 5,
+ publicMode: false,
+ userAccounts: false
+});
+
+export const mutations = {
+ set(state, config) {
+ Object.assign(state, config);
+ }
+};
diff --git a/src/site/store/images.js b/src/site/store/images.js
new file mode 100644
index 0000000..e87dac1
--- /dev/null
+++ b/src/site/store/images.js
@@ -0,0 +1,56 @@
+/* eslint-disable no-shadow */
+export const state = () => ({
+ files: [],
+ isLoading: false,
+ pagination: {
+ page: 1,
+ limit: 30,
+ totalFiles: 0
+ }
+});
+
+export const getters = {
+ getTotalFiles: state => state.pagination.totalFiles,
+ getFetchedCount: state => state.files.length,
+ shouldPaginate: ({ pagination }) => pagination.totalFiles > pagination.limit,
+ getLimit: ({ pagination }) => pagination.limit
+};
+
+export const actions = {
+ async fetch({ commit, dispatch, state }, page) {
+ commit('setIsLoading');
+
+ page = page || 1;
+
+ try {
+ const response = await this.$axios.$get(`files`, { params: { limit: state.pagination.limit, page } });
+
+ commit('updateFiles', { files: response.files });
+ commit('updatePaginationMeta', { totalFiles: response.count, page });
+ } catch (e) {
+ dispatch('alert/set', { text: e.message, error: true }, { root: true });
+ }
+ },
+ async fetchById({ commit, dispatch }) {
+ try {
+ const response = await this.$axios.$get('verify');
+ commit('loginSuccess', response);
+ } catch (e) {
+ dispatch('alert/set', { text: e.message, error: true }, { root: true });
+ }
+ }
+};
+
+export const mutations = {
+ setIsLoading(state) {
+ state.isLoading = true;
+ },
+ updateFiles(state, { files }) {
+ state.files = files || [];
+ state.isLoading = false;
+ },
+ updatePaginationMeta(state, { page, totalFiles }) {
+ state.pagination.page = page || 1;
+ state.pagination.totalFiles = totalFiles || 0;
+ }
+};
diff --git a/src/site/store/index.js b/src/site/store/index.js
index 1fc2272..8f910ae 100644
--- a/src/site/store/index.js
+++ b/src/site/store/index.js
@@ -1,66 +1,20 @@
import config from '../../../dist/config.json';
-export const state = () => ({
- loggedIn: false,
- user: null,
- token: null,
- config: null,
- alert: null
-});
-
-/* eslint-disable no-shadow */
-export const mutations = {
- loggedIn(state, payload) {
- state.loggedIn = payload;
- },
- user(state, payload) {
- state.user = payload;
- },
- token(state, payload) {
- state.token = payload;
- },
- config(state, payload) {
- state.config = payload;
- },
- alert(state, payload) {
- state.alert = payload;
- }
-};
export const actions = {
- async nuxtClientInit({ commit, dispatch }, { app, req }) {
- commit('config', config);
+ async nuxtClientInit({ commit, dispatch }) {
+ commit('config/set', config);
const cookies = this.$cookies.getAll();
- if (!cookies.token) return dispatch('logout');
+ if (!cookies.token) return dispatch('auth/logout');
- commit('token', cookies.token);
- try {
- const response = await this.$axios.$get('verify');
- dispatch('login', {
- token: cookies.token,
- user: response.user
- });
- } catch (error) {
- // dispatch('logout');
- }
- },
- login({ commit }, { token, user }) {
- this.$cookies.set('token', token);
- commit('token', token);
- commit('user', user);
- commit('loggedIn', true);
- },
- logout({ commit }) {
- this.$cookies.remove('token');
- commit('token', null);
- commit('user', null);
- commit('loggedIn', false);
- },
- alert({ commit }, payload) {
+ commit('auth/setToken', cookies.token);
+ await dispatch('auth/verify');
+ }
+ /* alert({ commit }, payload) {
if (!payload) return commit('alert', null);
commit('alert', {
text: payload.text,
error: payload.error
});
- }
+ } */
};