Work in progress

This commit is contained in:
Julien Nahum
2023-12-09 15:47:03 +01:00
parent f970557b76
commit 1f853e8178
315 changed files with 34058 additions and 25 deletions

71
client/stores/app.js vendored Normal file
View File

@@ -0,0 +1,71 @@
import { defineStore } from 'pinia'
import { nextTick } from 'vue'
export const useAppStore = defineStore('app', {
state: () => ({
layout: 'default',
// App Loader
loader: {
percent: 0,
show: false,
canSuccess: true,
duration: 3000,
_timer: null,
_cut: null
}
}),
actions: {
setLayout (layout) {
this.layout = layout ?? 'default'
},
loaderIncrease (num) {
this.loader.percent = this.loader.percent + Math.floor(num)
},
loaderDecrease (num) {
this.loader.percent = this.loader.percent - Math.floor(num)
},
loaderFinish () {
this.loader.percent = 100
this.loaderHide()
},
loaderSetTimer (timerVal) {
this.loader._timer = timerVal
},
loaderPause () {
clearInterval(this.loader._timer)
},
loaderHide () {
this.loaderPause()
this.loader._timer = null
setTimeout(() => {
this.loader.show = false
nextTick(() => {
setTimeout(() => {
this.loader.percent = 0
}, 200)
})
}, 500)
},
loaderFail () {
this.loader.canSuccess = false
},
loaderStart () {
this.loader.show = true
this.loader.canSuccess = true
if (this.loader._timer) {
clearInterval(this.loader._timer)
this.loader.percent = 0
}
this.loader._cut = 10000 / Math.floor(this.loader.duration)
this.loaderSetTimer(setInterval(() => {
this.loaderIncrease(this.loader._cut * Math.random())
if (this.loader.percent > 95) {
this.loaderFinish()
}
}, 100))
}
}
})

70
client/stores/auth.js vendored Normal file
View File

@@ -0,0 +1,70 @@
import { defineStore } from 'pinia'
import axios from 'axios'
import Cookies from 'js-cookie'
export const useAuthStore = defineStore('auth', {
state: () => ({
user: null,
token: Cookies.get('token'),
// For admin impersonation
admin_token: Cookies.get('admin_token') ?? null
}),
getters: {
check: (state) => (state.user !== null && state.user !== undefined),
isImpersonating: (state) => (state.admin_token !== null && state.admin_token !== undefined)
},
actions: {
// Stores admin token temporarily for impersonation
startImpersonating () {
this.admin_token = this.token
Cookies.set('admin_token', this.token, { expires: 365 })
},
// Stop admin impersonation
stopImpersonating () {
this.token = this.admin_token
this.admin_token = null
Cookies.set('token', this.token, { expires: 365 })
Cookies.remove('admin_token')
this.fetchUser()
},
saveToken (token, remember) {
this.token = token
Cookies.set('token', token, { expires: remember ? 365 : null })
},
async fetchUser () {
try {
const { data } = await axios.get('/api/user')
this.user = data
return data
} catch (e) {
this.token = null
Cookies.remove('token')
}
},
updateUser (payload) {
this.user = payload
},
load
async logout () {
try {
await axios.post('/api/logout')
} catch (e) { }
this.user = null
this.token = null
Cookies.remove('token')
},
async fetchOauthUrl (provider) {
const { data } = await axios.post(`/api/oauth/${provider}`)
return data.url
}
}
})

15
client/stores/errors.js vendored Normal file
View File

@@ -0,0 +1,15 @@
import { defineStore } from 'pinia'
export const useErrorsStore = defineStore('errors', {
state: () => ({
content: null
}),
actions: {
set (error) {
this.content = error
},
clear () {
this.content = null
}
}
})

82
client/stores/forms.js vendored Normal file
View File

@@ -0,0 +1,82 @@
import { defineStore } from 'pinia'
import axios from 'axios'
export const formsEndpoint = '/api/open/workspaces/{workspaceId}/forms'
export let currentPage = 1
export const useFormsStore = defineStore('forms', {
state: () => ({
content: [],
loading: false
}),
getters: {
getById: (state) => (id) => {
if (state.content.length === 0) return null
return state.content.find(item => item.id === id)
},
getBySlug: (state) => (slug) => {
if (state.content.length === 0) return null
return state.content.find(item => item.slug === slug)
},
getAllTags: (state) => {
if (state.content.length === 0) return []
let allTags = []
state.content.forEach(form => {
if(form.tags && form.tags.length > 0){
allTags = allTags.concat(form.tags)
}
})
return allTags.filter((item, i, ar) => ar.indexOf(item) === i)
}
},
actions: {
set (items) {
this.content = items
},
append (items) {
this.content = this.content.concat(items)
},
addOrUpdate (item) {
this.content = this.content.filter((val) => val.id !== item.id)
this.content.push(item)
},
remove (item) {
this.content = this.content.filter((val) => val.id !== item.id)
},
startLoading () {
this.loading = true
},
stopLoading () {
this.loading = false
},
resetState () {
this.set([])
this.stopLoading()
currentPage = 1
},
load (workspaceId) {
this.startLoading()
return axios.get(formsEndpoint.replace('{workspaceId}', workspaceId)+'?page='+currentPage).then((response) => {
if (currentPage == 1) {
this.set(response.data.data)
} else {
this.append(response.data.data)
}
if (currentPage < response.data.meta.last_page) {
currentPage += 1
this.load(workspaceId)
} else {
this.stopLoading()
currentPage = 1
}
})
},
loadIfEmpty (workspaceId) {
if (this.content.length === 0) {
return this.load(workspaceId)
}
this.stopLoading()
return Promise.resolve()
}
}
})

49
client/stores/records.js vendored Normal file
View File

@@ -0,0 +1,49 @@
import { defineStore } from 'pinia'
export const namespaced = true
/**
* Loads records from database
*/
export const useRecordsStore = defineStore('records', {
state: () => ({
content: [],
loading: false
}),
getters: {
getById: (state) => (id) => {
if (state.content.length === 0) return null
return state.content.find(item => item.submission_id === id)
}
},
actions: {
set (items) {
this.content = items
},
addOrUpdate (item) {
this.content = this.content.filter((val) => val.id !== item.id)
this.content.push(item)
},
remove (itemId) {
this.content = this.content.filter((val) => val.id !== itemId)
},
startLoading () {
this.loading = true
},
stopLoading () {
this.loading = false
},
resetState () {
this.set([])
this.stopLoading()
},
loadRecord (request) {
this.set([])
this.startLoading()
return request.then((data) => {
this.addOrUpdate(data)
this.stopLoading()
})
}
}
})

120
client/stores/templates.js vendored Normal file
View File

@@ -0,0 +1,120 @@
import axios from 'axios'
import { defineStore } from 'pinia'
export const templatesEndpoint = '/api/templates'
export const useTemplatesStore = defineStore('templates', {
state: () => ({
content: [],
industries: {},
types: {},
allLoaded: false,
loading: false
}),
getters: {
getBySlug: (state) => (slug) => {
if (state.content.length === 0) return null
return state.content.find(item => item.slug === slug)
},
getTemplateTypes: (state) => (slugs) => {
if (state.types.length === 0) return null
return Object.values(state.types).filter((val) => slugs.includes(val.slug)).map((item) => { return item.name })
},
getTemplateIndustries: (state) => (slugs) => {
if (state.industries.length === 0) return null
return Object.values(state.industries).filter((val) => slugs.includes(val.slug)).map((item) => { return item.name })
}
},
actions: {
set (items) {
this.content = items
this.allLoaded = true
},
append (items) {
const ids = items.map((item) => { return item.id })
this.content = this.content.filter((val) => !ids.includes(val.id))
this.content = this.content.concat(items)
},
addOrUpdate (item) {
this.content = this.content.filter((val) => val.id !== item.id)
this.content.push(item)
},
remove (item) {
this.content = this.content.filter((val) => val.id !== item.id)
},
startLoading () {
this.loading = true
},
stopLoading () {
this.loading = false
},
setAllLoaded (val) {
this.allLoaded = val
},
resetState () {
this.set([])
this.stopLoading()
},
loadTypesAndIndustries () {
if (Object.keys(this.industries).length === 0) {
import('@/data/forms/templates/industries.json').then((module) => {
this.industries = module.default
})
}
if (Object.keys(this.types).length === 0) {
import('@/data/forms/templates/types.json').then((module) => {
this.types = module.default
})
}
},
loadTemplate (slug) {
this.startLoading()
this.loadTypesAndIndustries()
if (this.getBySlug(slug)) {
this.stopLoading()
return Promise.resolve()
}
return axios.get(templatesEndpoint + '/' + slug).then((response) => {
this.addOrUpdate(response.data)
this.stopLoading()
}).catch((error) => {
this.stopLoading()
})
},
loadAll (options=null) {
this.startLoading()
this.loadTypesAndIndustries()
// Prepare with options
let queryStr = ''
if(options !== null){
for (const [key, value] of Object.entries(options)) {
queryStr += '&' + encodeURIComponent(key) + '=' + encodeURIComponent(value)
}
queryStr = queryStr.slice(1)
}
return axios.get((queryStr) ? templatesEndpoint + '?' + queryStr : templatesEndpoint).then((response) => {
if(options !== null){
this.set(response.data)
this.setAllLoaded(false)
} else {
this.append(response.data)
this.setAllLoaded(true)
}
this.stopLoading()
}).catch((error) => {
this.stopLoading()
})
},
loadIfEmpty () {
if (!this.allLoaded) {
return this.loadAll()
}
this.stopLoading()
return Promise.resolve()
}
}
})

50
client/stores/working_form.js vendored Normal file
View File

@@ -0,0 +1,50 @@
import { defineStore } from 'pinia'
export const useWorkingFormStore = defineStore('working_form', {
state: () => ({
content: null,
// Field being edited
selectedFieldIndex: null,
showEditFieldSidebar: null,
showAddFieldSidebar: null
}),
actions: {
set (form) {
this.content = form
},
setProperties (properties) {
this.content.properties = properties
},
openSettingsForField (index) {
// If field is passed, compute index
if (typeof index === 'object') {
index = this.content.properties.findIndex(prop => prop.id === index.id)
}
this.selectedFieldIndex = index
this.showEditFieldSidebar = true
this.showAddFieldSidebar = false
},
closeEditFieldSidebar () {
this.selectedFieldIndex = null
this.showEditFieldSidebar = false
this.showAddFieldSidebar = false
},
openAddFieldSidebar (index) {
// If field is passed, compute index
if (index !== null && typeof index === 'object') {
index = this.content.properties.findIndex(prop => prop.id === index.id)
}
this.selectedFieldIndex = index
this.showAddFieldSidebar = true
this.showEditFieldSidebar = false
},
closeAddFieldSidebar () {
this.selectedFieldIndex = null
this.showAddFieldSidebar = false
this.showEditFieldSidebar = false
}
}
})

95
client/stores/workspaces.js vendored Normal file
View File

@@ -0,0 +1,95 @@
import axios from 'axios'
import { defineStore } from 'pinia'
export const workspaceEndpoint = '/api/open/workspaces/'
const localStorageCurrentWorkspaceKey = 'currentWorkspace'
export const useWorkspacesStore = defineStore('workspaces', {
state: () => ({
content: [],
currentId: null,
loading: false
}),
getters: {
getById: (state) => (id) => {
if (state.content.length === 0) return null
return state.content.find(item => item.id === id)
},
getCurrent: (state) => () => {
if (state.content.length === 0 || state.currentId === null) return null
return state.content.find(item => item.id === state.currentId)
}
},
actions: {
set (items) {
this.content = items
if (this.currentId == null && this.content.length > 0) {
// If one only, set it
if (this.content.length === 1) {
this.currentId = items[0].id
localStorage.setItem(localStorageCurrentWorkspaceKey, this.currentId)
} else if (localStorage.getItem(localStorageCurrentWorkspaceKey) && this.content.find(item => item.id === parseInt(localStorage.getItem(localStorageCurrentWorkspaceKey)))) {
// Check local storage for current workspace, or take first
this.currentId = parseInt(localStorage.getItem(localStorageCurrentWorkspaceKey))
localStorage.setItem(localStorageCurrentWorkspaceKey, this.currentId)
} else {
// Else, take first
this.currentId = items[0].id
localStorage.setItem(localStorageCurrentWorkspaceKey, this.currentId)
}
} else {
localStorage.removeItem(localStorageCurrentWorkspaceKey)
}
},
setCurrentId (id) {
this.currentId = id
localStorage.setItem(localStorageCurrentWorkspaceKey, id)
},
addOrUpdate (item) {
this.content = this.content.filter((val) => val.id !== item.id)
this.content.push(item)
if (this.currentId == null) {
this.currentId = item.id
localStorage.setItem(localStorageCurrentWorkspaceKey, this.currentId)
}
},
remove (itemId) {
this.content = this.content.filter((val) => val.id !== itemId)
if (this.currentId === itemId) {
this.currentId = this.content.length > 0 ? this.content[0].id : null
localStorage.setItem(localStorageCurrentWorkspaceKey, this.currentId)
}
},
startLoading () {
this.loading = true
},
stopLoading () {
this.loading = false
},
resetState () {
this.set([])
this.stopLoading()
},
load () {
this.set([])
this.startLoading()
return axios.get(workspaceEndpoint).then((response) => {
this.set(response.data)
this.stopLoading()
})
},
loadIfEmpty () {
if (this.content.length === 0) {
return this.load()
}
return Promise.resolve()
},
delete (id) {
this.startLoading()
return axios.delete(workspaceEndpoint + id).then((response) => {
this.remove(response.data.workspace_id)
this.stopLoading()
})
}
}
})