🎉 First commit, from couchbase generator, basic changes
not tested / updated yet
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
import { getStoreAccessors } from 'typesafe-vuex';
|
||||
import { State } from '@/store/state';
|
||||
import { mutations } from '../mutations';
|
||||
import { AdminState } from '../state';
|
||||
|
||||
const {commit} = getStoreAccessors<AdminState, State>('');
|
||||
|
||||
export const commitSetRoles = commit(mutations.setRoles);
|
||||
export const commitSetUser = commit(mutations.setUser);
|
||||
export const commitSetUsers = commit(mutations.setUsers);
|
||||
@@ -0,0 +1,11 @@
|
||||
import { getStoreAccessors } from 'typesafe-vuex';
|
||||
import { AdminState } from '../state';
|
||||
import { State } from '@/store/state';
|
||||
import { actions } from '../actions';
|
||||
|
||||
const {dispatch} = getStoreAccessors<AdminState, State>('');
|
||||
|
||||
export const dispatchCreateUser = dispatch(actions.actionCreateUser);
|
||||
export const dispatchGetRoles = dispatch(actions.actionGetRoles);
|
||||
export const dispatchGetUsers = dispatch(actions.actionGetUsers);
|
||||
export const dispatchUpdateUser = dispatch(actions.actionUpdateUser);
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './commit';
|
||||
export * from './dispatch';
|
||||
export * from './read';
|
||||
@@ -0,0 +1,10 @@
|
||||
import { getStoreAccessors } from 'typesafe-vuex';
|
||||
import { AdminState } from '../state';
|
||||
import { State } from '@/store/state';
|
||||
import { getters } from '../getters';
|
||||
|
||||
const { read } = getStoreAccessors<AdminState, State>('');
|
||||
|
||||
export const readAdminOneUser = read(getters.adminOneUser);
|
||||
export const readAdminRoles = read(getters.adminRoles);
|
||||
export const readAdminUsers = read(getters.adminUsers);
|
||||
@@ -0,0 +1,64 @@
|
||||
import { api } from '@/api';
|
||||
import { ActionContext } from 'vuex';
|
||||
import {
|
||||
commitSetUsers,
|
||||
commitSetUser,
|
||||
commitSetRoles,
|
||||
} from './accessors/commit';
|
||||
import { IUserProfileCreate, IUserProfileUpdate } from '@/interfaces';
|
||||
import { State } from '../state';
|
||||
import { AdminState } from './state';
|
||||
import { dispatchCheckApiError, commitAddNotification, commitRemoveNotification } from '../main/accessors';
|
||||
|
||||
type MainContext = ActionContext<AdminState, State>;
|
||||
|
||||
export const actions = {
|
||||
async actionGetUsers(context: MainContext) {
|
||||
try {
|
||||
const response = await api.getUsers(context.rootState.main.token);
|
||||
if (response) {
|
||||
commitSetUsers(context, response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
await dispatchCheckApiError(context, error);
|
||||
}
|
||||
},
|
||||
async actionUpdateUser(context: MainContext, payload: { name: string, user: IUserProfileUpdate }) {
|
||||
try {
|
||||
const loadingNotification = { content: 'saving', showProgress: true };
|
||||
commitAddNotification(context, loadingNotification);
|
||||
const response = (await Promise.all([
|
||||
api.updateUser(context.rootState.main.token, payload.name, payload.user),
|
||||
await new Promise((resolve, reject) => setTimeout(() => resolve(), 500)),
|
||||
]))[0];
|
||||
commitSetUser(context, response.data);
|
||||
commitRemoveNotification(context, loadingNotification);
|
||||
commitAddNotification(context, {content: 'User successfully updated', color: 'success'});
|
||||
} catch (error) {
|
||||
await dispatchCheckApiError(context, error);
|
||||
}
|
||||
},
|
||||
async actionCreateUser(context: MainContext, payload: IUserProfileCreate) {
|
||||
try {
|
||||
const loadingNotification = { content: 'saving', showProgress: true };
|
||||
commitAddNotification(context, loadingNotification);
|
||||
const response = (await Promise.all([
|
||||
api.createUser(context.rootState.main.token, payload),
|
||||
await new Promise((resolve, reject) => setTimeout(() => resolve(), 500)),
|
||||
]))[0];
|
||||
commitSetUser(context, response.data);
|
||||
commitRemoveNotification(context, loadingNotification);
|
||||
commitAddNotification(context, { content: 'User successfully created', color: 'success' });
|
||||
} catch (error) {
|
||||
await dispatchCheckApiError(context, error);
|
||||
}
|
||||
},
|
||||
async actionGetRoles(context: MainContext) {
|
||||
try {
|
||||
const response = await api.getRoles(context.rootState.main.token);
|
||||
commitSetRoles(context, response.data.roles);
|
||||
} catch (error) {
|
||||
await dispatchCheckApiError(context, error);
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
import { AdminState } from './state';
|
||||
|
||||
export const getters = {
|
||||
adminUsers: (state: AdminState) => state.users,
|
||||
adminRoles: (state: AdminState) => state.roles,
|
||||
adminOneUser: (state: AdminState) => (name: string) => {
|
||||
const filteredUsers = state.users.filter((user) => user.name === name);
|
||||
if (filteredUsers.length > 0) {
|
||||
return { ...filteredUsers[0] };
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
import { mutations } from './mutations';
|
||||
import { getters } from './getters';
|
||||
import { actions } from './actions';
|
||||
import { AdminState } from './state';
|
||||
|
||||
const defaultState: AdminState = {
|
||||
users: [],
|
||||
roles: [],
|
||||
};
|
||||
|
||||
export const adminModule = {
|
||||
state: defaultState,
|
||||
mutations,
|
||||
actions,
|
||||
getters,
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
import { IUserProfile } from '@/interfaces';
|
||||
import { AdminState } from './state';
|
||||
|
||||
export const mutations = {
|
||||
setUsers(state: AdminState, payload: IUserProfile[]) {
|
||||
state.users = payload;
|
||||
},
|
||||
setUser(state: AdminState, payload: IUserProfile) {
|
||||
const users = state.users.filter((user: IUserProfile) => user.name !== payload.name);
|
||||
users.push(payload);
|
||||
state.users = users;
|
||||
},
|
||||
setRoles(state: AdminState, payload: string[]) {
|
||||
state.roles = payload;
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,6 @@
|
||||
import { IUserProfile } from '@/interfaces';
|
||||
|
||||
export interface AdminState {
|
||||
users: IUserProfile[];
|
||||
roles: string[];
|
||||
}
|
||||
19
{{cookiecutter.project_slug}}/frontend/src/store/index.ts
Normal file
19
{{cookiecutter.project_slug}}/frontend/src/store/index.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import Vue from 'vue';
|
||||
import Vuex, { StoreOptions } from 'vuex';
|
||||
|
||||
import { mainModule } from './main';
|
||||
import { State } from './state';
|
||||
import { adminModule } from './admin';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
const storeOptions: StoreOptions<State> = {
|
||||
modules: {
|
||||
main: mainModule,
|
||||
admin: adminModule,
|
||||
},
|
||||
};
|
||||
|
||||
export const store = new Vuex.Store<State>(storeOptions);
|
||||
|
||||
export default store;
|
||||
@@ -0,0 +1,15 @@
|
||||
import { getStoreAccessors } from 'typesafe-vuex';
|
||||
import { MainState } from '../state';
|
||||
import { State } from '@/store/state';
|
||||
import { mutations } from '../mutations';
|
||||
|
||||
const {commit} = getStoreAccessors<MainState | any, State>('');
|
||||
|
||||
export const commitSetDashboardMiniDrawer = commit(mutations.setDashboardMiniDrawer);
|
||||
export const commitSetDashboardShowDrawer = commit(mutations.setDashboardShowDrawer);
|
||||
export const commitSetLoggedIn = commit(mutations.setLoggedIn);
|
||||
export const commitSetLogInError = commit(mutations.setLogInError);
|
||||
export const commitSetToken = commit(mutations.setToken);
|
||||
export const commitSetUserProfile = commit(mutations.setUserProfile);
|
||||
export const commitAddNotification = commit(mutations.addNotification);
|
||||
export const commitRemoveNotification = commit(mutations.removeNotification);
|
||||
@@ -0,0 +1,20 @@
|
||||
import { getStoreAccessors } from 'typesafe-vuex';
|
||||
import { MainState } from '../state';
|
||||
import { State } from '@/store/state';
|
||||
import { actions } from '../actions';
|
||||
|
||||
const {dispatch} = getStoreAccessors<MainState | any, State>('');
|
||||
|
||||
export const dispatchCheckApiError = dispatch(actions.actionCheckApiError);
|
||||
export const dispatchCheckLoggedIn = dispatch(actions.actionCheckLoggedIn);
|
||||
export const dispatchGetUserProfile = dispatch(actions.actionGetUserProfile);
|
||||
export const dispatchLogIn = dispatch(actions.actionLogIn);
|
||||
export const dispatchLogOut = dispatch(actions.actionLogOut);
|
||||
export const dispatchUserLogOut = dispatch(actions.actionUserLogOut);
|
||||
export const dispatchRemoveLogIn = dispatch(actions.actionRemoveLogIn);
|
||||
export const dispatchRouteLoggedIn = dispatch(actions.actionRouteLoggedIn);
|
||||
export const dispatchRouteLogOut = dispatch(actions.actionRouteLogOut);
|
||||
export const dispatchUpdateUserProfile = dispatch(actions.actionUpdateUserProfile);
|
||||
export const dispatchRemoveNotification = dispatch(actions.removeNotification);
|
||||
export const dispatchPasswordRecovery = dispatch(actions.passwordRecovery);
|
||||
export const dispatchResetPassword = dispatch(actions.resetPassword);
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from './commit';
|
||||
export * from './dispatch';
|
||||
export * from './read';
|
||||
@@ -0,0 +1,15 @@
|
||||
import { getStoreAccessors } from 'typesafe-vuex';
|
||||
import { MainState } from '../state';
|
||||
import { State } from '@/store/state';
|
||||
import { getters } from '../getters';
|
||||
|
||||
const {read} = getStoreAccessors<MainState, State>('');
|
||||
|
||||
export const readDashboardMiniDrawer = read(getters.dashboardMiniDrawer);
|
||||
export const readDashboardShowDrawer = read(getters.dashboardShowDrawer);
|
||||
export const readHasAdminAccess = read(getters.hasAdminAccess);
|
||||
export const readIsLoggedIn = read(getters.isLoggedIn);
|
||||
export const readLoginError = read(getters.loginError);
|
||||
export const readToken = read(getters.token);
|
||||
export const readUserProfile = read(getters.userProfile);
|
||||
export const readFirstNotification = read(getters.firstNotification);
|
||||
163
{{cookiecutter.project_slug}}/frontend/src/store/main/actions.ts
Normal file
163
{{cookiecutter.project_slug}}/frontend/src/store/main/actions.ts
Normal file
@@ -0,0 +1,163 @@
|
||||
import { api } from '@/api';
|
||||
import { saveLocalToken, getLocalToken, removeLocalToken } from '@/utils';
|
||||
import router from '@/router';
|
||||
import { ActionContext } from 'vuex';
|
||||
import {
|
||||
commitSetToken,
|
||||
commitSetLoggedIn,
|
||||
commitSetLogInError,
|
||||
dispatchGetUserProfile,
|
||||
dispatchRouteLoggedIn,
|
||||
dispatchLogOut,
|
||||
commitSetUserProfile,
|
||||
dispatchCheckApiError,
|
||||
dispatchRemoveLogIn,
|
||||
dispatchRouteLogOut,
|
||||
commitRemoveNotification,
|
||||
commitAddNotification,
|
||||
} from './accessors';
|
||||
import { AxiosError } from 'axios';
|
||||
import { IUserProfileCreate, IUserProfileUpdate } from '@/interfaces';
|
||||
import { State } from '../state';
|
||||
import { MainState, AppNotification } from './state';
|
||||
|
||||
type MainContext = ActionContext<MainState, State>;
|
||||
|
||||
export const actions = {
|
||||
async actionLogIn(context: MainContext, payload: { username: string; password: string }) {
|
||||
try {
|
||||
const response = await api.logInGetToken(payload.username, payload.password);
|
||||
const token = response.data.access_token;
|
||||
if (token) {
|
||||
saveLocalToken(token);
|
||||
commitSetToken(context, token);
|
||||
commitSetLoggedIn(context, true);
|
||||
commitSetLogInError(context, false);
|
||||
await dispatchGetUserProfile(context);
|
||||
await dispatchRouteLoggedIn(context);
|
||||
commitAddNotification(context, { content: 'Logged in', color: 'success' });
|
||||
} else {
|
||||
await dispatchLogOut(context);
|
||||
}
|
||||
} catch (err) {
|
||||
commitSetLogInError(context, true);
|
||||
await dispatchLogOut(context);
|
||||
}
|
||||
},
|
||||
async actionGetUserProfile(context: MainContext) {
|
||||
try {
|
||||
const response = await api.getMe(context.state.token);
|
||||
if (response.data) {
|
||||
commitSetUserProfile(context, response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
await dispatchCheckApiError(context, error);
|
||||
}
|
||||
},
|
||||
async actionUpdateUserProfile(context: MainContext, payload) {
|
||||
try {
|
||||
const loadingNotification = { content: 'saving', showProgress: true };
|
||||
commitAddNotification(context, loadingNotification);
|
||||
const response = (await Promise.all([
|
||||
api.updateMe(context.state.token, payload),
|
||||
await new Promise((resolve, reject) => setTimeout(() => resolve(), 500)),
|
||||
]))[0];
|
||||
commitSetUserProfile(context, response.data);
|
||||
commitRemoveNotification(context, loadingNotification);
|
||||
commitAddNotification(context, { content: 'Profile successfully updated', color: 'success' });
|
||||
} catch (error) {
|
||||
await dispatchCheckApiError(context, error);
|
||||
}
|
||||
},
|
||||
async actionCheckLoggedIn(context: MainContext) {
|
||||
if (!context.state.isLoggedIn) {
|
||||
let token = context.state.token;
|
||||
if (!token) {
|
||||
const localToken = getLocalToken();
|
||||
if (localToken) {
|
||||
commitSetToken(context, localToken);
|
||||
token = localToken;
|
||||
}
|
||||
}
|
||||
if (token) {
|
||||
try {
|
||||
const response = await api.getMe(token);
|
||||
commitSetLoggedIn(context, true);
|
||||
commitSetUserProfile(context, response.data);
|
||||
} catch (error) {
|
||||
await dispatchRemoveLogIn(context);
|
||||
}
|
||||
} else {
|
||||
await dispatchRemoveLogIn(context);
|
||||
}
|
||||
}
|
||||
},
|
||||
async actionRemoveLogIn(context: MainContext) {
|
||||
removeLocalToken();
|
||||
commitSetToken(context, '');
|
||||
commitSetLoggedIn(context, false);
|
||||
},
|
||||
async actionLogOut(context: MainContext) {
|
||||
await dispatchRemoveLogIn(context);
|
||||
await dispatchRouteLogOut(context);
|
||||
},
|
||||
async actionUserLogOut(context: MainContext) {
|
||||
await dispatchLogOut(context);
|
||||
commitAddNotification(context, { content: 'Logged out', color: 'success' });
|
||||
},
|
||||
actionRouteLogOut(context: MainContext) {
|
||||
if (router.currentRoute.path !== '/login') {
|
||||
router.push('/login');
|
||||
}
|
||||
},
|
||||
async actionCheckApiError(context: MainContext, payload: AxiosError) {
|
||||
if (payload.response!.status === 401) {
|
||||
await dispatchLogOut(context);
|
||||
}
|
||||
},
|
||||
actionRouteLoggedIn(context: MainContext) {
|
||||
if (router.currentRoute.path === '/login' || router.currentRoute.path === '/') {
|
||||
router.push('/main');
|
||||
}
|
||||
},
|
||||
async removeNotification(context: MainContext, payload: { notification: AppNotification, timeout: number }) {
|
||||
return new Promise((resolve, reject) => {
|
||||
setTimeout(() => {
|
||||
commitRemoveNotification(context, payload.notification);
|
||||
resolve(true);
|
||||
}, payload.timeout);
|
||||
});
|
||||
},
|
||||
async passwordRecovery(context: MainContext, payload: { username: string }) {
|
||||
const loadingNotification = { content: 'Sending password recovery email', showProgress: true };
|
||||
try {
|
||||
commitAddNotification(context, loadingNotification);
|
||||
const response = (await Promise.all([
|
||||
api.passwordRecovery(payload.username),
|
||||
await new Promise((resolve, reject) => setTimeout(() => resolve(), 500)),
|
||||
]))[0];
|
||||
commitRemoveNotification(context, loadingNotification);
|
||||
commitAddNotification(context, { content: 'Password recovery email sent', color: 'success' });
|
||||
await dispatchLogOut(context);
|
||||
} catch (error) {
|
||||
commitRemoveNotification(context, loadingNotification);
|
||||
commitAddNotification(context, { color: 'error', content: 'Incorrect username' });
|
||||
}
|
||||
},
|
||||
async resetPassword(context: MainContext, payload: { password: string, token: string }) {
|
||||
const loadingNotification = { content: 'Resetting password', showProgress: true };
|
||||
try {
|
||||
commitAddNotification(context, loadingNotification);
|
||||
const response = (await Promise.all([
|
||||
api.resetPassword(payload.password, payload.token),
|
||||
await new Promise((resolve, reject) => setTimeout(() => resolve(), 500)),
|
||||
]))[0];
|
||||
commitRemoveNotification(context, loadingNotification);
|
||||
commitAddNotification(context, { content: 'Password successfully reset', color: 'success' });
|
||||
await dispatchLogOut(context);
|
||||
} catch (error) {
|
||||
commitRemoveNotification(context, loadingNotification);
|
||||
commitAddNotification(context, { color: 'error', content: 'Error resetting password' });
|
||||
}
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,16 @@
|
||||
import { MainState } from './state';
|
||||
|
||||
export const getters = {
|
||||
hasAdminAccess: (state: MainState) => {
|
||||
return (
|
||||
state.userProfile &&
|
||||
state.userProfile.admin_roles.includes('superuser'));
|
||||
},
|
||||
loginError: (state: MainState) => state.logInError,
|
||||
dashboardShowDrawer: (state: MainState) => state.dashboardShowDrawer,
|
||||
dashboardMiniDrawer: (state: MainState) => state.dashboardMiniDrawer,
|
||||
userProfile: (state: MainState) => state.userProfile,
|
||||
token: (state: MainState) => state.token,
|
||||
isLoggedIn: (state: MainState) => state.isLoggedIn,
|
||||
firstNotification: (state: MainState) => state.notifications.length > 0 && state.notifications[0],
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
import { mutations } from './mutations';
|
||||
import { getters } from './getters';
|
||||
import { actions } from './actions';
|
||||
import { MainState } from './state';
|
||||
|
||||
const defaultState: MainState = {
|
||||
isLoggedIn: null,
|
||||
token: '',
|
||||
logInError: false,
|
||||
userProfile: null,
|
||||
dashboardMiniDrawer: false,
|
||||
dashboardShowDrawer: true,
|
||||
notifications: [],
|
||||
};
|
||||
|
||||
export const mainModule = {
|
||||
state: defaultState,
|
||||
mutations,
|
||||
actions,
|
||||
getters,
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
import { IUserProfile } from '@/interfaces';
|
||||
import { MainState, AppNotification } from './state';
|
||||
|
||||
|
||||
export const mutations = {
|
||||
setToken(state: MainState, payload: string) {
|
||||
state.token = payload;
|
||||
},
|
||||
setLoggedIn(state: MainState, payload: boolean) {
|
||||
state.isLoggedIn = payload;
|
||||
},
|
||||
setLogInError(state: MainState, payload: boolean) {
|
||||
state.logInError = payload;
|
||||
},
|
||||
setUserProfile(state: MainState, payload: IUserProfile) {
|
||||
state.userProfile = payload;
|
||||
},
|
||||
setDashboardMiniDrawer(state: MainState, payload: boolean) {
|
||||
state.dashboardMiniDrawer = payload;
|
||||
},
|
||||
setDashboardShowDrawer(state: MainState, payload: boolean) {
|
||||
state.dashboardShowDrawer = payload;
|
||||
},
|
||||
addNotification(state: MainState, payload: AppNotification) {
|
||||
state.notifications.push(payload);
|
||||
},
|
||||
removeNotification(state: MainState, payload: AppNotification) {
|
||||
state.notifications = state.notifications.filter((notification) => notification !== payload);
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,17 @@
|
||||
import { IUserProfile } from '@/interfaces';
|
||||
|
||||
export interface AppNotification {
|
||||
content: string;
|
||||
color?: string;
|
||||
showProgress?: boolean;
|
||||
}
|
||||
|
||||
export interface MainState {
|
||||
token: string;
|
||||
isLoggedIn: boolean | null;
|
||||
logInError: boolean;
|
||||
userProfile: IUserProfile | null;
|
||||
dashboardMiniDrawer: boolean;
|
||||
dashboardShowDrawer: boolean;
|
||||
notifications: AppNotification[];
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
import { MainState } from './main/state';
|
||||
|
||||
export interface State {
|
||||
main: MainState;
|
||||
}
|
||||
Reference in New Issue
Block a user