Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

apply first submission modal changes #584

Merged
merged 9 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions api/app/Http/Controllers/Forms/PublicFormController.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ public function showAsset($assetFileName)
public function answer(AnswerFormRequest $request)
{
$form = $request->form;
$isFirstSubmission = ($form->submissions_count === 0);
$submissionId = false;

$submissionData = $request->validated();
Expand All @@ -104,6 +105,7 @@ public function answer(AnswerFormRequest $request)
return $this->success(array_merge([
'message' => 'Form submission saved.',
'submission_id' => $submissionId,
'is_first_submission' => $isFirstSubmission
], $request->form->is_pro && $request->form->redirect_url ? [
'redirect' => true,
'redirect_url' => $request->form->redirect_url,
Expand Down
1 change: 1 addition & 0 deletions api/app/Http/Resources/FormResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public function toArray($request)
'views_count' => $this->views_count,
'submissions_count' => $this->submissions_count,
'redirect_url' => $this->redirect_url,
'submissions_url' => $this->submissions_url,
'database_fields_update' => $this->database_fields_update,
'cleanings' => $this->getCleanigns(),
'can_be_indexed' => $this->can_be_indexed,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix typo in method name: getCleanigns() should be getCleanings()

There's a typo in the method name getCleanigns(). This should be corrected to getCleanings() for clarity and consistency. Although this isn't directly related to the changes in this PR, it's a good opportunity to fix it to prevent potential issues in the future.

Here's the suggested fix:

-            'cleanings' => $this->getCleanigns(),
+            'cleanings' => $this->getCleanings(),

Also, please update the method name at the bottom of the file:

-    private function getCleanigns()
+    private function getCleanings()
     {
         return $this->extra?->cleanings ?? $this->cleanings;
     }

Committable suggestion was skipped due to low confidence.

Expand Down
9 changes: 9 additions & 0 deletions api/app/Models/Forms/Form.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,15 @@ public function getShareUrlAttribute()
return front_url('/forms/' . $this->slug);
}

public function getSubmissionsUrlAttribute()
{
if ($this->custom_domain) {
return 'https://' . $this->custom_domain . '/forms/' . $this->slug . '/show/submissions';
}

return front_url('/forms/' . $this->slug . '/show/submissions');
}

public function getEditUrlAttribute()
{
return front_url('/forms/' . $this->slug . '/show');
Expand Down
21 changes: 18 additions & 3 deletions client/components/open/forms/OpenCompleteForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,11 @@
</p>
</div>
</v-transition>
<FirstSubmissionModal
:show="showFirstSubmissionModal"
:form="form"
@close="showFirstSubmissionModal=false"
/>
</div>
</template>

Expand All @@ -191,9 +196,10 @@ import VTransition from '~/components/global/transitions/VTransition.vue'
import {pendingSubmission} from "~/composables/forms/pendingSubmission.js"
import clonedeep from "clone-deep"
import ThemeBuilder from "~/lib/forms/themes/ThemeBuilder.js"
import FirstSubmissionModal from '~/components/open/forms/components/FirstSubmissionModal.vue'

export default {
components: { VTransition, OpenFormButton, OpenForm, FormCleanings, FormTimer },
components: { VTransition, OpenFormButton, OpenForm, FormCleanings, FormTimer, FirstSubmissionModal },

props: {
form: { type: Object, required: true },
Expand All @@ -207,7 +213,10 @@ export default {
},

setup(props) {
const authStore = useAuthStore()
return {
authStore,
authenticated: computed(() => authStore.check),
isIframe: useIsIframe(),
pendingSubmission: pendingSubmission(props.form),
confetti: useConfetti()
Expand All @@ -222,7 +231,8 @@ export default {
password: null
}),
hidePasswordDisabledMsg: false,
submissionId: false
submissionId: false,
showFirstSubmissionModal: false
}
},

Expand All @@ -246,6 +256,9 @@ export default {
if(!this.form || !this.form.font_family) return null
const family = this.form?.font_family.replace(/ /g, '+')
return `https://fonts.googleapis.com/css?family=${family}:wght@400,500,700,800,900&display=swap`
},
isFormOwner() {
return this.authenticated && this.form && this.form.creator_id === this.authStore.user.id
}
},

Expand Down Expand Up @@ -291,7 +304,9 @@ export default {
if (data.submission_id) {
this.submissionId = data.submission_id
}

if (this.isFormOwner && !this.isIframe && data?.is_first_submission) {
this.showFirstSubmissionModal = true
}
this.loading = false
this.submitted = true
this.$emit('submitted', true)
Expand Down
48 changes: 24 additions & 24 deletions client/components/open/forms/components/FirstSubmissionModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,29 @@
</template>
<div class="">
<div class="text-sm text-gray-500">
Congratulations on creating your form and receiving your first submission! Your form is now live and ready for action. You can now <span class="font-semibold">share your form</span> with others, or <span class="font-semibold">open your Notion database</span> to view the submitted data.
Congratulations on creating your form and receiving your first submission! Your form is now live and ready for action. You can now <span class="font-semibold">share your form</span> with others, or <span class="font-semibold">open your Form submission page</span> to view the submitted data.
</div>

<div class="flex gap-2 items-center max-w-full">
<p class="text-sm w-48 text-gray-500">
Share form URL:
</p>
<ShareFormUrl
class="flex-grow my-4"
:form="form"
/>
</div>
<div class="flex py-2 items-center max-w-full">
<p class="text-sm w-48 text-gray-500">
Check your submissions:
</p>
<UButton
v-track.form_first_submission_modal_open_db_click
color="white"
icon="i-logos-notion-icon"
:to="form.notion_database_url"
icon="i-heroicons-document"
target="_blank"
@click="trackOpenDbClick"
>
See Notion database
See Submissions
</UButton>
</div>

Expand All @@ -39,19 +46,19 @@
v-for="(item, i) in helpLinks"
:key="i"
role="button"
class="bg-white shadow border border-gray-200 rounded-lg p-4 pb-2 items-center justify-center flex flex-col relative hover:bg-gray-50 group transition-colors"
class="bg-white shadow border border-gray-200 rounded-lg p-4 pb-2 items-center justify-center flex flex-col relative hover:bg-gray-50 dark:hover:bg-gray-800 group transition-colors"
@click="item.action"
>
<div class="flex justify-center">
<div class="h-8 w-8 text-gray-600 group-hover:text-gray-800 transition-colors flex items-center">
<div class="h-8 w-8 text-gray-600 group-hover:text-gray-800 dark:group-hover:text-white transition-colors flex items-center">
<Icon
:name="item.icon"
class=""
size="40px"
/>
</div>
</div>

<p class="text-gray-500 font-medium text-xs text-center my-2">
{{ item.label }}
</p>
Expand All @@ -62,36 +69,23 @@
</template>

<script setup>
import ShareFormUrl from '~/components/notion/forms/components/ShareFormUrl.vue'

import ShareFormUrl from '~/components/open/forms/components/ShareFormUrl.vue'
const props = defineProps({
show: { type: Boolean, required: true },
form: { type: Object, required: true }
})

const emit = defineEmits(['close'])
const confetti = useConfetti()
const crisp = useCrisp()

const amplitude = useAmplitude()
watch(() => props.show, () => {
if (props.show) {
confetti.play()
useAmplitude().logEvent('form_first_submission_modal_viewed')
}
})

const helpLinks = computed(() => {
return [
{
'label': 'Embed form on your website',
'icon': 'heroicons:code-bracket',
'action': () => crisp.openHelpdeskArticle('how-to-embed-your-form-on-your-website-yqa6i')
},
{
'label': 'Embed form in Notion',
'icon': 'ri:notion-fill',
'action': () => crisp.openHelpdeskArticle('can-i-embed-my-form-in-a-notion-page-or-site-11iroj9')
},
{
'label': 'Help Center',
'icon': 'heroicons:book-open',
Expand All @@ -105,4 +99,10 @@ const helpLinks = computed(() => {
]
})

</script>
const trackOpenDbClick = () => {
const submissionsUrl = props.form.submissions_url
window.open(submissionsUrl, '_blank')
amplitude.logEvent('form_first_submission_modal_open_db_click')
}

</script>
70 changes: 70 additions & 0 deletions client/components/open/forms/components/ShareFormUrl.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<template>
<div
class="border border-nt-blue-light bg-blue-50 dark:bg-notion-dark-light rounded-md p-2 overflow-hidden"
>
<div class="flex items-center w-full gap-2">
<p class="select-all text-nt-blue flex-grow truncate overflow-hidden">
<a
v-if="link"
:href="share_url"
target="_blank"
>
{{ share_url }}
</a>
<span v-else>
{{ share_url }}
</span>
</p>
<UButton
class="shrink-0"
size="sm"
icon="i-heroicons-clipboard-document"
label="Copy"
@click="copyToClipboard"
/>
</div>
</div>
</template>

<script setup>
import { computed, defineProps } from 'vue'

const props = defineProps({
form: {
type: Object,
required: true,
},
link: {
type: Boolean,
default: false,
},
extraQueryParam: {
type: String,
default: '',
},
})

const { copy } = useClipboard()

const share_url = computed(() => {
if (props.extraQueryParam) {
return `${props.form.share_url}?${props.extraQueryParam}`
}
return props.form.share_url
})

function copyToClipboard() {
if (import.meta.server)
return
copy(share_url.value)
if (props.form.visibility == 'draft') {
useAlert().warning(
'Copied! But other people won\'t be able to see the form since it\'s currently in draft mode',
)
}
else {
useAlert().success('Copied!')
}
}
Comment on lines +56 to +68
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider implementing async/await and error handling in copyToClipboard.

While the function logic is correct, it could be improved by implementing async/await and adding error handling as suggested in the past review comments.

Consider updating the function as follows:

async function copyToClipboard() {
  if (import.meta.server)
    return
  try {
    await copy(share_url.value)
    if (props.form.visibility === 'draft') {
      useAlert().warning(
        'Copied! But other people won\'t be able to see the form since it\'s currently in draft mode',
      )
    } else {
      useAlert().success('Copied!')
    }
  } catch (error) {
    useAlert().error('Failed to copy URL')
  }
}

This change adds error handling and ensures the alert is shown only after the copy operation is complete.

</script>

2 changes: 1 addition & 1 deletion client/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export default defineNuxtConfig({
...process.env.NUXT_PUBLIC_GTM_CODE ? ['@zadigetvoltaire/nuxt-gtm'] : [],
],
build: {
transpile: process.env.NODE_ENV === "development" ? [] : ["vue-notion", "query-builder-vue-3", "vue-signature-pad"],
transpile: ["vue-notion", "query-builder-vue-3", "vue-signature-pad"],
},
experimental: {
inlineRouteRules: true
Expand Down
Loading
Loading