Multiple bug fixing

This commit is contained in:
Julien Nahum 2024-02-10 12:20:45 +01:00
parent f2916b9e31
commit 91911bc6e5
16 changed files with 51 additions and 51 deletions

View File

@ -4,7 +4,7 @@
ref="scrollContainer" ref="scrollContainer"
:class="[$style['scroll-container'],{'no-scrollbar':hideScrollbar}]" :class="[$style['scroll-container'],{'no-scrollbar':hideScrollbar}]"
:style="{ width: width?width:'auto', height }" :style="{ width: width?width:'auto', height }"
@scroll.passive="toggleShadow" @scroll.passive="throttled.toggleShadow"
> >
<slot /> <slot />
<span :class="[$style['shadow-top'], shadow.top && $style['is-active']]" :style="{ <span :class="[$style['shadow-top'], shadow.top && $style['is-active']]" :style="{
@ -19,6 +19,7 @@
</template> </template>
<script> <script>
import throttle from 'lodash.throttle'
function newResizeObserver (callback) { function newResizeObserver (callback) {
// Skip this feature for browsers which // Skip this feature for browsers which
// do not support ResizeObserver. // do not support ResizeObserver.
@ -50,28 +51,31 @@ export default {
bottom: false, bottom: false,
left: false left: false
}, },
debounceTimeout: null,
scrollContainerObserver: null, scrollContainerObserver: null,
wrapObserver: null wrapObserver: null,
throttled: {}
} }
}, },
mounted () { mounted () {
window.addEventListener('resize', this.calcDimensions) this.throttled.toggleShadow = throttle(this.toggleShadow, 100);
this.throttled.calcDimensions = throttle(this.calcDimensions, 100);
window.addEventListener('resize', this.throttled.calcDimensions)
// Check if shadows are necessary after the element is resized. // Check if shadows are necessary after the element is resized.
const scrollContainerObserver = newResizeObserver(this.toggleShadow) const scrollContainerObserver = newResizeObserver(this.throttled.toggleShadow)
if (scrollContainerObserver) { if (scrollContainerObserver) {
scrollContainerObserver.observe(this.$refs.scrollContainer) scrollContainerObserver.observe(this.$refs.scrollContainer)
} }
// Recalculate the container dimensions when the wrapper is resized. // Recalculate the container dimensions when the wrapper is resized.
this.wrapObserver = newResizeObserver(this.calcDimensions) this.wrapObserver = newResizeObserver(this.throttled.calcDimensions)
if (this.wrapObserver) { if (this.wrapObserver) {
this.wrapObserver.observe(this.$el) this.wrapObserver.observe(this.$el)
} }
}, },
unmounted () { unmounted () {
window.removeEventListener('resize', this.calcDimensions) window.removeEventListener('resize', this.throttled.calcDimensions)
// Cleanup when the component is unmounted. // Cleanup when the component is unmounted.
this.wrapObserver.disconnect() this.wrapObserver.disconnect()
if (this.scrollContainerObserver) { if (this.scrollContainerObserver) {

View File

@ -173,6 +173,7 @@ export default {
*/ */
currentFieldsPageBreak () { currentFieldsPageBreak () {
// Last block from current group // Last block from current group
if (!this.currentFields?.length) return null
const block = this.currentFields[this.currentFields.length - 1] const block = this.currentFields[this.currentFields.length - 1]
if (block && block.type === 'nf-page-break') return block if (block && block.type === 'nf-page-break') return block
return null return null

View File

@ -97,6 +97,7 @@ import FormCustomSeo from './form-components/FormCustomSeo.vue'
import FormAccess from './form-components/FormAccess.vue' import FormAccess from './form-components/FormAccess.vue'
import {validatePropertiesLogic} from "~/composables/forms/validatePropertiesLogic.js" import {validatePropertiesLogic} from "~/composables/forms/validatePropertiesLogic.js"
import opnformConfig from "~/opnform.config.js"; import opnformConfig from "~/opnform.config.js";
import {captureException} from "@sentry/vue";
export default { export default {
name: 'FormEditor', name: 'FormEditor',
@ -255,9 +256,12 @@ export default {
this.amplitude.logEvent('form_saved', { form_id: this.form.id, form_slug: this.form.slug }) this.amplitude.logEvent('form_saved', { form_id: this.form.id, form_slug: this.form.slug })
this.displayFormModificationAlert(data) this.displayFormModificationAlert(data)
}).catch((error) => { }).catch((error) => {
if (error.response.status === 422) { if (error?.response.status === 422) {
this.validationErrorResponse = error.response.data this.validationErrorResponse = error.response.data
this.showValidationErrors() this.showValidationErrors()
} else {
useAlert().error('An error occurred while saving the form, please try again.')
captureException(error)
} }
}).finally(() => { }).finally(() => {
this.updateFormLoading = false this.updateFormLoading = false
@ -282,10 +286,12 @@ export default {
this.displayFormModificationAlert(response) this.displayFormModificationAlert(response)
useRouter().push({ name: 'forms-slug-show-share', params: { slug: this.createdFormSlug, new_form: response.users_first_form } }) useRouter().push({ name: 'forms-slug-show-share', params: { slug: this.createdFormSlug, new_form: response.users_first_form } })
}).catch((error) => { }).catch((error) => {
console.error(error) if (error?.response?.status === 422) {
if (error.response && error.response.status === 422) {
this.validationErrorResponse = error.response this.validationErrorResponse = error.response
this.showValidationErrors() this.showValidationErrors()
} else {
useAlert().error('An error occurred while saving the form, please try again.')
captureException(error)
} }
}).finally(() => { }).finally(() => {
this.updateFormLoading = false this.updateFormLoading = false

View File

@ -17,11 +17,6 @@
]" ]"
:form="form" label="Form Theme" :form="form" label="Form Theme"
/> />
<div class="-mt-3 mb-3 text-gray-400 dark:text-gray-500">
<small>
Need another theme? <a href="#" @click.prevent="crisp.openAndShowChat">Send us some suggestions!</a>
</small>
</div>
<select-input name="dark_mode" class="mt-4" <select-input name="dark_mode" class="mt-4"
help="To see changes, save your form and open it" help="To see changes, save your form and open it"

View File

@ -468,6 +468,7 @@ export default {
return true return true
}, },
optionsText () { optionsText () {
if (this.field[this.field.type]) return []
return this.field[this.field.type].options.map(option => { return this.field[this.field.type].options.map(option => {
return option.name return option.name
}).join('\n') }).join('\n')

View File

@ -53,8 +53,8 @@
<td v-if="hasActions" class="n-table-cell border-gray-100 dark:border-gray-900 text-sm p-2 border-b" <td v-if="hasActions" class="n-table-cell border-gray-100 dark:border-gray-900 text-sm p-2 border-b"
style="width: 100px" style="width: 100px"
> >
<record-operations :form="form" :structure="columns" :submission="row" <record-operations :form="form" :structure="columns" :submission="row"
@deleted="(submission)=>$emit('deleted',submission)" @deleted="(submission)=>$emit('deleted',submission)"
@updated="(submission)=>$emit('updated', submission)"/> @updated="(submission)=>$emit('updated', submission)"/>
</td> </td>
</tr> </tr>
@ -91,7 +91,7 @@ import {hash} from "~/lib/utils.js";
export default { export default {
components: {ResizableTh, RecordOperations}, components: {ResizableTh, RecordOperations},
emits: ["updated", "deleted"], emits: ["updated", "deleted", "resize"],
props: { props: {
columns: { columns: {
type: Array, type: Array,

View File

@ -145,7 +145,9 @@ export default {
this.fetchGeneratedForm(generationId) this.fetchGeneratedForm(generationId)
} }
}).catch(error => { }).catch(error => {
this.useAlert.error(error.data.message) if (error?.data?.message){
this.useAlert.error(error.data.message)
}
this.state = 'default' this.state = 'default'
this.loading = false this.loading = false
}) })

View File

@ -25,7 +25,6 @@ export const useCrisp = () => {
function openAndShowChat(message = null) { function openAndShowChat(message = null) {
if (!crisp) return if (!crisp) return
showChat()
openChat() openChat()
if (message) sendTextMessage(message) if (message) sendTextMessage(message)
} }

View File

@ -65,7 +65,7 @@ function checkContains (condition, fieldValue) {
function checkListContains (condition, fieldValue) { function checkListContains (condition, fieldValue) {
if (!fieldValue) return false if (!fieldValue) return false
if (Array.isArray(condition.value)) { if (Array.isArray(condition.value)) {
return condition.value.every(r => fieldValue.includes(r)) return condition.value.every(r => fieldValue.includes(r))
} else { } else {
@ -74,11 +74,11 @@ function checkListContains (condition, fieldValue) {
} }
function checkStartsWith (condition, fieldValue) { function checkStartsWith (condition, fieldValue) {
return fieldValue.startsWith(condition.value) return fieldValue?.startsWith(condition.value)
} }
function checkendsWith (condition, fieldValue) { function checkendsWith (condition, fieldValue) {
return fieldValue && fieldValue.endsWith(condition.value) return fieldValue?.endsWith(condition.value)
} }
function checkIsEmpty (condition, fieldValue) { function checkIsEmpty (condition, fieldValue) {

View File

@ -28,6 +28,7 @@
"fuse.js": "^6.4.6", "fuse.js": "^6.4.6",
"js-sha256": "^0.10.0", "js-sha256": "^0.10.0",
"libphonenumber-js": "^1.10.44", "libphonenumber-js": "^1.10.44",
"lodash.throttle": "^4.1.1",
"nuxt3-notifications": "^1.1.9", "nuxt3-notifications": "^1.1.9",
"object-to-formdata": "^4.5.1", "object-to-formdata": "^4.5.1",
"pinia": "^2.1.7", "pinia": "^2.1.7",
@ -8517,6 +8518,11 @@
"lodash._reinterpolate": "^3.0.0" "lodash._reinterpolate": "^3.0.0"
} }
}, },
"node_modules/lodash.throttle": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
"integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ=="
},
"node_modules/lodash.uniq": { "node_modules/lodash.uniq": {
"version": "4.5.0", "version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",

View File

@ -43,6 +43,7 @@
"fuse.js": "^6.4.6", "fuse.js": "^6.4.6",
"js-sha256": "^0.10.0", "js-sha256": "^0.10.0",
"libphonenumber-js": "^1.10.44", "libphonenumber-js": "^1.10.44",
"lodash.throttle": "^4.1.1",
"nuxt3-notifications": "^1.1.9", "nuxt3-notifications": "^1.1.9",
"object-to-formdata": "^4.5.1", "object-to-formdata": "^4.5.1",
"pinia": "^2.1.7", "pinia": "^2.1.7",

View File

@ -33,7 +33,9 @@ const error = ref(null)
const formInitialHash = ref(null) const formInitialHash = ref(null)
function isDirty() { function isDirty() {
return formInitialHash.value && updatedForm.value && formInitialHash.value !== hash(JSON.stringify(updatedForm.value.data() ?? null)) return formInitialHash.value &&
updatedForm.value &&
formInitialHash.value !== hash(JSON.stringify(updatedForm?.value?.data() ?? null))
} }
function initUpdatedForm() { function initUpdatedForm() {

View File

@ -71,14 +71,14 @@
} }
] ]
if (user.value.is_subscribed) { if (user?.value?.is_subscribed) {
tabs.splice(1, 0, { tabs.splice(1, 0, {
name: 'Billing', name: 'Billing',
route: 'settings-billing' route: 'settings-billing'
}) })
} }
if (user.value.admin) { if (user?.value?.admin) {
tabs.push({ tabs.push({
name: 'Admin', name: 'Admin',
route: 'settings-admin' route: 'settings-admin'

View File

@ -1,16 +1,5 @@
import * as Sentry from "@sentry/vue"; import * as Sentry from "@sentry/vue";
async function lazyLoadSentryIntegrations() {
// don't load on server
if (!process.client) return;
const {Replay} = await import("@sentry/vue");
Sentry.addIntegration(new Replay({
maskAllText: false,
blockAllMedia: false,
}));
}
function getSentryIntegrations() { function getSentryIntegrations() {
// don't load on server // don't load on server
if (!process.client) return []; if (!process.client) return [];
@ -65,8 +54,5 @@ export default defineNuxtPlugin({
return event; return event;
}, },
}) })
// Lazy-load the replay integration to reduce bundle size
lazyLoadSentryIntegrations()
} }
}); });

17
client/stores/auth.js vendored
View File

@ -1,4 +1,5 @@
import {defineStore} from 'pinia' import {defineStore} from 'pinia'
import {setUser as sentrySetUser} from "@sentry/vue";
export const useAuthStore = defineStore('auth', { export const useAuthStore = defineStore('auth', {
state: () => { state: () => {
@ -65,18 +66,16 @@ export const useAuthStore = defineStore('auth', {
useCrisp().setUser(this.user) useCrisp().setUser(this.user)
// Init sentry // Init sentry
// console.log(process) sentrySetUser({
// $sentry.configureScope((scope) => { id: this.user.id,
// scope.setUser({ email: this.user.email,
// id: this.user.id, subscription: this.user?.is_subscribed
// email: this.user.email, })
// subscription: this.user?.is_subscribed
// })
// })
}, },
logout() { logout() {
opnFetch('logout', {method: 'POST'}).catch((error) => {}) opnFetch('logout', {method: 'POST'}).catch((error) => {
})
this.user = null this.user = null
this.setToken(null) this.setToken(null)

View File

@ -1,7 +1,5 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
export const useWorkingFormStore = defineStore('working_form', { export const useWorkingFormStore = defineStore('working_form', {
state: () => ({ state: () => ({
content: null, content: null,