Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
JhumanJ committed Dec 14, 2023
1 parent 5c4dc2a commit a3a9254
Show file tree
Hide file tree
Showing 24 changed files with 445 additions and 122 deletions.
2 changes: 1 addition & 1 deletion client/components/forms/useFormInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export function useFormInput (props, context, formPrefixKey = null) {
})

const hasError = computed(() => {
return hasValidation && props.form?.errors?.has(name)
return hasValidation && props.form?.errors?.has(props.name)
})

const compVal = computed({
Expand Down
7 changes: 2 additions & 5 deletions client/components/global/Modal.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<portal to="modals" :order="portalOrder">
<Teleport to="body">
<transition @leave="(el,done) => motions.backdrop.leave(done)">
<div v-if="show" v-motion="'backdrop'" :variants="motionFadeIn"
class="fixed z-30 top-0 inset-0 px-4 sm:px-0 flex items-top justify-center bg-gray-700/75 w-full h-screen overflow-y-scroll"
Expand Down Expand Up @@ -46,7 +46,7 @@
</div>
</div>
</transition>
</portal>
</Teleport>
</template>

<script>
Expand All @@ -71,9 +71,6 @@ export default {
},
closeable: {
default: true
},
portalOrder: {
default: 1
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ export default {
]
},
init () {
if (this.$route.name === 'forms.create' || this.$route.name === 'forms-create-guest') { // Set Default fields
if (this.$route.name === 'forms-create' || this.$route.name === 'forms-create-guest') { // Set Default fields
this.formFields = (this.form.properties.length > 0) ? clonedeep(this.form.properties) : this.getDefaultFields()
} else {
this.formFields = clonedeep(this.form.properties).map((field) => {
Expand Down
13 changes: 3 additions & 10 deletions client/components/pages/auth/components/LoginForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,12 @@
</template>

<script>
import { computed } from 'vue'
import Form from 'vform'
import Cookies from 'js-cookie'
import { useAuthStore } from '../../../../stores/auth.js'
import OpenFormFooter from '../../OpenFormFooter.vue'
import Testimonials from '../../welcome/Testimonials.vue'
import ForgotPasswordModal from '../ForgotPasswordModal.vue'
export default {
name: 'LoginForm',
components: {
OpenFormFooter,
Testimonials,
ForgotPasswordModal
},
props: {
Expand All @@ -72,7 +65,7 @@ export default {
},
data: () => ({
form: new Form({
form: useForm({
email: '',
password: ''
}),
Expand All @@ -83,10 +76,10 @@ export default {
methods: {
async login () {
// Submit the form.
const { data } = await this.form.post('/api/login')
const data = await this.form.post('login')
// Save the token.
this.authStore.saveToken(data.token, this.remember)
this.authStore.setToken(data.token, this.remember)
// Fetch the user.
await this.authStore.fetchUser()
Expand Down
2 changes: 1 addition & 1 deletion client/components/pages/auth/components/RegisterForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export default {
if (this.isQuick) {
this.$emit('afterQuickLogin')
} else {
this.$router.push({ name: 'forms.create' })
this.$router.push({ name: 'forms-create' })
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion client/components/pages/welcome/AiFeature.vue
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
<!-- <v-button v-if="!authenticated" class="mr-2 block" :to="{ name: 'forms-create-guest' }" :arrow="true">-->
<!-- Get started for free-->
<!-- </v-button>-->
<!-- <v-button v-else class="mr-2 block" :to="{ name: 'forms.create' }" :arrow="true">-->
<!-- <v-button v-else class="mr-2 block" :to="{ name: 'forms-create' }" :arrow="true">-->
<!-- Get started for free-->
<!-- </v-button>-->
<!-- <v-button color="light-gray" class="mr-1 block" :to="{ name: 'aiformbuilder' }">-->
Expand Down
75 changes: 75 additions & 0 deletions client/composables/lib/vForm/Errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@

function arrayWrap(value) {
return Array.isArray(value) ? value : [value];
}

export default class Errors {
constructor() {
this.errors = {};
}

set(field, messages = undefined) {
if (typeof field === 'object') {
this.errors = field;
} else {
this.set({ ...this.errors, [field]: arrayWrap(messages) });
}
}

all() {
return this.errors;
}

has(field) {
return Object.prototype.hasOwnProperty.call(this.errors, field);
}

hasAny(...fields) {
return fields.some(field => this.has(field));
}

any() {
return Object.keys(this.errors).length > 0;
}

get(field) {
if (this.has(field)) {
return this.getAll(field)[0];
}
}

getAll(field) {
return arrayWrap(this.errors[field] || []);
}

only(...fields) {
const messages = [];

fields.forEach((field) => {
const message = this.get(field);
if (message) {
messages.push(message);
}
});

return messages;
}

flatten() {
return Object.values(this.errors).reduce((a, b) => a.concat(b), []);
}

clear(field = undefined) {
const errors = {};

if (field) {
Object.keys(this.errors).forEach((key) => {
if (key !== field) {
errors[key] = this.errors[key];
}
});
}

this.set(errors);
}
}
175 changes: 175 additions & 0 deletions client/composables/lib/vForm/Form.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import {serialize} from 'object-to-formdata';
import Errors from './Errors';
import cloneDeep from 'clone-deep';
import {useOpnFetch} from "~/composables/useOpnFetch.js";

function hasFiles(data) {
return data instanceof File ||
data instanceof Blob ||
data instanceof FileList ||
(typeof data === 'object' && data !== null && Object.values(data).find(value => hasFiles(value)) !== undefined);
}

class Form {
constructor(data = {}) {
this.originalData = {};
this.busy = false;
this.successful = false;
this.recentlySuccessful = false;
this.recentlySuccessfulTimeoutId = undefined;
this.errors = new Errors();
this.update(data);
}

static errorMessage = 'Something went wrong. Please try again.';
static recentlySuccessfulTimeout = 2000;
static ignore = ['busy', 'successful', 'errors', 'originalData', 'recentlySuccessful', 'recentlySuccessfulTimeoutId'];

static make(augment) {
return new this(augment);
}

update(data) {
this.originalData = Object.assign({}, this.originalData, cloneDeep(data));
Object.assign(this, data);
}

fill(data = {}) {
this.keys().forEach((key) => {
this[key] = data[key];
});
}

data() {
return this.keys().reduce((data, key) => (
{...data, [key]: this[key]}
), {});
}

keys() {
return Object.keys(this).filter(key => !Form.ignore.includes(key));
}

startProcessing() {
this.errors.clear();
this.busy = true;
this.successful = false;
this.recentlySuccessful = false;
clearTimeout(this.recentlySuccessfulTimeoutId);
}

finishProcessing() {
this.busy = false;
this.successful = true;
this.recentlySuccessful = true;
this.recentlySuccessfulTimeoutId = setTimeout(() => {
this.recentlySuccessful = false;
}, Form.recentlySuccessfulTimeout);
}

clear() {
this.errors.clear();
this.successful = false;
this.recentlySuccessful = false;
clearTimeout(this.recentlySuccessfulTimeoutId);
}

reset() {
Object.keys(this)
.filter(key => !Form.ignore.includes(key))
.forEach((key) => {
this[key] = deepCopy(this.originalData[key]);
});
}

get(url, config = {}) {
return this.submit('get', url, config);
}

post(url, config = {}) {
return this.submit('post', url, config);
}

patch(url, config = {}) {
return this.submit('patch', url, config);
}

put(url, config = {}) {
return this.submit('put', url, config);
}

delete(url, config = {}) {
return this.submit('delete', url, config);
}

submit(method, url, config = {}) {
this.startProcessing();

config = {
body: {},
params: {},
url: url,
method: method,
...config
};

if (method.toLowerCase() === 'get') {
config.params = {...this.data(), ...config.params};
} else {
config.body = {...this.data(), ...config.data};

if (hasFiles(config.data) && !config.transformRequest) {
config.transformRequest = [data => serialize(data)];
}
}

return new Promise((resolve, reject) => {
useOpnFetch(config.url, config)
.then(({data, error}) => {
if (error.value) {
this.handleErrors(error);
reject(error);
return;
}

this.finishProcessing();
resolve(data.value);
})
});
}

handleErrors(error) {
this.busy = false;

if (error.value) {
this.errors.set(this.extractErrors(error.value.data));
}
}

extractErrors(data) {
if (!data || typeof data !== 'object') {
return {error: Form.errorMessage};

}

if (data.errors) {
return {...data.errors};
}

if (data.message) {
return {error: data.message};
}

return {...data};
}

onKeydown(event) {
const target = event.target;

if (target.name) {
this.errors.clear(target.name);
}
}
}

export default Form;
5 changes: 5 additions & 0 deletions client/composables/useForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import Form from "~/composables/lib/vForm/Form.js"

export const useForm = (formData) => {
return new Form(formData)
}
5 changes: 5 additions & 0 deletions client/composables/useOpnFetch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import config from "~/opnform.config.js";

export const useOpnFetch = (request, opts) => {
return useFetch(request, { baseURL: config.api_url, ...opts })
}
8 changes: 8 additions & 0 deletions client/middleware/admin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import {useAuthStore} from "../../resources/js/stores/auth.js";

export default defineNuxtRouteMiddleware((to, from) => {
const authStore = useAuthStore()
if (!authStore.user?.admin) {
navigateTo({ name: 'home' })
}
})
11 changes: 11 additions & 0 deletions client/middleware/auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import {useAuthStore} from "../../resources/js/stores/auth.js";

export default defineNuxtRouteMiddleware((to, from) => {
const authStore = useAuthStore()

if (!authStore.check) {
useCookie('intended_url').value = to.path

navigateTo({ name: 'login' })
}
})
5 changes: 5 additions & 0 deletions client/middleware/check-auth.global.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default defineNuxtRouteMiddleware((to, from) => {
const authStore = useAuthStore()
authStore.loadTokenFromCookie()
useAuthStore().fetchUserIfNotFetched()
})
Loading

0 comments on commit a3a9254

Please sign in to comment.