Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
19 changes: 19 additions & 0 deletions forms_pro/api/form.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,25 @@ class FormSharedWithResponse(BaseModel):
submit: bool


@frappe.whitelist(allow_guest=True)
def is_login_required(route: str) -> bool:
"""
Check if login is enabled for a form.

args:
route: str - The route of the form to check.

returns:
bool - True if login is required, False otherwise.
"""
login_enabled = frappe.db.get_value(
doctype="Form",
filters={"route": route},
fieldname="login_required",
)
return bool(login_enabled)
Comment on lines +20 to +36
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Fix docstring parameter name and verify None handling.

Two concerns:

  1. Documentation error: The docstring references form_id in the args section, but the parameter is named route.
  2. Silent failure for non-existent routes: When frappe.db.get_value returns None (route doesn't exist), bool(None) returns False, making non-existent forms appear as "login not required". Consider if this is the desired behavior or if you should explicitly handle the non-existent route case.
🔎 Proposed fix for docstring
     """
     Check if login is enabled for a form.
 
     args:
-        form_id: str - The ID of the form to check.
+        route: str - The route of the form to check.
 
     returns:
         bool - True if login is required, False otherwise.
     """
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@frappe.whitelist(allow_guest=True)
def is_login_required(route: str) -> bool:
"""
Check if login is enabled for a form.
args:
form_id: str - The ID of the form to check.
returns:
bool - True if login is required, False otherwise.
"""
login_enabled = frappe.db.get_value(
doctype="Form",
filters={"route": route},
fieldname="login_required",
)
return bool(login_enabled)
@frappe.whitelist(allow_guest=True)
def is_login_required(route: str) -> bool:
"""
Check if login is enabled for a form.
args:
route: str - The route of the form to check.
returns:
bool - True if login is required, False otherwise.
"""
login_enabled = frappe.db.get_value(
doctype="Form",
filters={"route": route},
fieldname="login_required",
)
return bool(login_enabled)
🤖 Prompt for AI Agents
In forms_pro/api/form.py around lines 20 to 36, fix the docstring to reference
the actual parameter name "route" and correct the returns description, and add
explicit handling for when frappe.db.get_value returns None (non-existent route)
instead of silently treating it as False; if login_enabled is None raise a clear
exception (e.g. frappe.DoesNotExistError or frappe.throw with a descriptive
message) so callers know the route was not found, otherwise return
bool(login_enabled).



@frappe.whitelist(allow_guest=True)
def get_form_by_route(route: str) -> dict:
form_id = frappe.db.get_value("Form", {"route": route}, pluck="name")
Expand Down
13 changes: 13 additions & 0 deletions forms_pro/api/settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import frappe
from frappe.core.doctype.navbar_settings.navbar_settings import get_app_logo


@frappe.whitelist(allow_guest=True)
def get_brand_logo() -> str:
"""
Get the brand logo for the form.

Returns:
str: The brand logo of the website or the default app logo if brand logo is not set.
"""
return str(get_app_logo())
Comment on lines +1 to +13
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Jan 2, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find the get_app_logo function definition in the Frappe codebase
find . -type f -name "*.py" | head -20

Repository: BuildWithHussain/forms_pro

Length of output: 917


🏁 Script executed:

# Search for get_app_logo function definition
rg -n "def get_app_logo" --type=py -A 15

Repository: BuildWithHussain/forms_pro

Length of output: 52


🏁 Script executed:

# Search for imports of get_app_logo and usage patterns
rg -n "get_app_logo" --type=py | head -30

Repository: BuildWithHussain/forms_pro

Length of output: 234


🌐 Web query:

Frappe get_app_logo function guest context allow_guest

💡 Result:

Short answer — use website context or a guest-allowed endpoint.

Steps:

  1. For static/logo values, set them via hooks (website_context) or implement update_website_context to add logo paths (this is available to website pages, including Guest). Example in hooks.py:

    • website_context = {"favicon": "/assets/your_app/img/favicon.png", "splash_image": "/files/your_logo.png"}
    • or implement update_website_context = "your_app.overrides.website_context" and set context["brand_html"] / context["banner_image"]. [1]
  2. If you need to call a Python method from client-side code to return the app logo, expose that method with @frappe.whitelist(allow_guest=True) so Guest can call it. Note: allow_guest=True only lets the Guest call the method — it does not bypass permission checks inside the method, so ensure you only access data that guests may read. [2][3]

References:

  • website_context / update_website_context (hooks) documentation. [1]
  • @frappe.whitelist(allow_guest=True) and guest-method behavior / forum guidance. [2][3]

If you want, tell me whether you need an example update_website_context implementation or a whitelisted method snippet.


🌐 Web query:

frappe.core.doctype.navbar_settings get_app_logo source code

💡 Result:

The function is implemented in the Navbar Settings DocType class at:
frappe/core/doctype/navbar_settings/navbar_settings.py — method get_app_logo (i.e. frappe.core.doctype.navbar_settings.navbar_settings.get_app_logo). See the Frappe repo and endpoint listing for reference. [1][2]

Sources:

  • Frappe GitHub repository (code tree root). [1]
  • Whitelisted endpoints listing showing the exact import path. [2]

🌐 Web query:

site:github.com frappe get_app_logo implementation navbar_settings

💡 Result:

I searched GitHub for Frappe references to get_app_logo and navbar/navbar_settings. Relevant repo issues and threads discussing navbar/app logo behavior and Website Settings include:

  • "Website Settings > Login Page > 'App Logo' doesn't change the App Logo" (frappe/frappe). [1]
  • "App logo Not changing after changing navbar logo" (frappe/erpnext). [2]
  • Example traceback referencing navbar/header image usage in ERPNext templates (frappe/erpnext). [3]

If you want, I can (a) search for the exact function/implementation file that computes/returns the app logo within the Frappe codebase, or (b) open the specific files in the frappe/erpnext repos to locate where navbar_settings or get_app_logo are implemented. Which would you like next?


🏁 Script executed:

# Try to find if get_app_logo is documented in Frappe or if there's any error handling pattern
rg -i "get_app_logo|navbar_settings" --type=py

Repository: BuildWithHussain/forms_pro

Length of output: 229


🌐 Web query:

frappe navbar_settings.py get_app_logo def source code implementation

💡 Result:

I couldn't find a definitive copy of navbar_settings.py/get_app_logo across public Frappe sources. Which Frappe version or repository (GitHub URL or your site) should I look in? I can fetch and paste the exact function once you point me to the correct branch/repo/version.


🌐 Web query:

"def get_app_logo" frappe source

💡 Result:

I couldn't find a function named def get_app_logo in the Frappe codebase. Frappe exposes app/logo via hooks and website settings instead — e.g. the login page uses frappe.get_website_settings("app_logo") or the hooks value app_logo_url (frappe.get_hooks("app_logo_url")[-1]). See the hooks docs and the forum discussion for the code references. [1][2]

Sources:

  • Frappe hooks documentation (lists app_logo_url hook). [1]
  • Forum snippet showing login/signup using frappe.get_website_settings("app_logo") or frappe.get_hooks("app_logo_url")[-1]. [2]

🏁 Script executed:

# Look for test files that might exercise this code
find . -name "*test*.py" | xargs grep -l "get_brand_logo\|settings" 2>/dev/null | head -10

Repository: BuildWithHussain/forms_pro

Length of output: 52


🏁 Script executed:

# Check if there are any requirements or setup files specifying Frappe version
find . -name "requirements.txt" -o -name "setup.py" -o -name "pyproject.toml" | xargs cat 2>/dev/null

Repository: BuildWithHussain/forms_pro

Length of output: 1103


🏁 Script executed:

# Search for any error handling or try-catch around the get_app_logo import
rg -B5 -A5 "get_app_logo" --type=py

Repository: BuildWithHussain/forms_pro

Length of output: 756


Verify get_app_logo() exists and add error handling for guest context.

The web search could not find get_app_logo() in the Frappe codebase—Frappe typically uses hooks (app_logo_url) or website_settings("app_logo") instead. Even if the function exists, @frappe.whitelist(allow_guest=True) does not bypass permission checks inside the called function, so verify it works safely with guest users. Additionally, the function call lacks any try-catch block to handle potential exceptions when accessed in a guest context.

Confirm the import path and add error handling:

@frappe.whitelist(allow_guest=True)
def get_brand_logo() -> str:
    """
    Get the brand logo for the form.

    Returns:
        str: The brand logo of the website or the default app logo if brand logo is not set.
    """
    try:
        return str(get_app_logo())
    except Exception as e:
        # Return a fallback or log the error
        frappe.logger().warning(f"Failed to get app logo: {e}")
        return ""
🤖 Prompt for AI Agents
In forms_pro/api/settings.py around lines 1-13, verify that get_app_logo is a
valid import from frappe (if not, use the standard website settings/app_logo
hook such as website_settings("app_logo") or app_logo_url) and make the function
safe for guest access by wrapping the call in a try/except: call the verified
logo getter inside try, log any exception with frappe.logger().warning including
the exception details, and return a safe fallback (empty string or configured
default) on error so guest requests never raise; ensure no privileged APIs are
invoked that require authentication.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It exists in frappe's codebase

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

1 change: 1 addition & 0 deletions frontend/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ declare module 'vue' {
FormHeader: typeof import('./src/components/submission/FormHeader.vue')['default']
FormPreviewCard: typeof import('./src/components/dashboard/FormPreviewCard.vue')['default']
FormRenderer: typeof import('./src/components/submission/FormRenderer.vue')['default']
PageHeader: typeof import('./src/components/submission/PageHeader.vue')['default']
RemoveAccessModal: typeof import('./src/components/form/manage/RemoveAccessModal.vue')['default']
RenderField: typeof import('./src/components/RenderField.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
Expand Down
21 changes: 15 additions & 6 deletions frontend/src/components/FormBuilderHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,21 @@ const router = useRouter();
const editFormStore = useEditForm();

const openFormSubmissionPage = () => {
const routeData = router.resolve({
name: "Form Submission Page",
params: {
route: editFormStore.originalFormData?.route,
},
});
const route = editFormStore.originalFormData?.route;
if (!route) return;

// Why router.resolve() with named route + params doesn't work:
// Vue Router URL-encodes parameter values when using the params object,
// even with catch-all routes. So a route like "s/something" becomes "s%2Fsomething".
//
// Solution: Get the route definition and construct the path manually,
// then use router.resolve() with the path string (which doesn't get encoded).
// This way, if the path changes in router.ts, this code still works.
const routeRecord = router.getRoutes().find((r) => r.name === "Form Submission Page");
if (!routeRecord) return;

const path = routeRecord.path.replace(":route(.*)", route);
const routeData = router.resolve(path);

window.open(routeData.href, "_blank");
};
Expand Down
17 changes: 6 additions & 11 deletions frontend/src/components/RenderField.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script setup>
import { formFields } from "@/utils/form_fields";
<script setup lang="ts">
import { FormFields, formFields, FormFieldType } from "@/utils/form_fields";
import { computed } from "vue";

const props = defineProps({
field: {
type: Object,
Expand All @@ -10,15 +11,9 @@ const props = defineProps({

const value = defineModel();
const getComponent = computed(() => {
return formFields.find((field) => field.name === props.field.fieldtype);
});

const getBinds = computed(() => {
return {
...props.field,
...props.field.options,
...props.field.default,
};
return formFields.find(
(field: FormFields) => field.name === props.field.fieldtype
) as FormFieldType;
});
Comment on lines 13 to 17
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential runtime error when field type is not found.

formFields.find() returns undefined if no matching field type exists. The cast to FormFieldType silences the TypeScript error but doesn't prevent the runtime crash when accessing getComponent.component in the template.

🔎 Proposed fix with fallback handling
 const getComponent = computed(() => {
-    return formFields.find(
+    const found = formFields.find(
         (field: FormFields) => field.name === props.field.fieldtype
-    ) as FormFieldType;
+    );
+    if (!found) {
+        console.warn(`Unknown field type: ${props.field.fieldtype}`);
+        return DataField; // fallback to DataField
+    }
+    return found;
 });

You'll need to import DataField from @/utils/form_fields as the fallback.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In frontend/src/components/RenderField.vue around lines 13 to 17, getComponent
currently casts the result of formFields.find(...) to FormFieldType which can be
undefined at runtime; update the computed to import DataField from
"@/utils/form_fields" and use it as a safe fallback when find returns undefined
(i.e., return the found FormFieldType or DataField), removing the unsafe cast so
the template can always access getComponent.component without crashing.

</script>
<template>
Expand Down
12 changes: 2 additions & 10 deletions frontend/src/components/builder/FieldRenderer.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<script setup>
<script setup lang="ts">
import { computed } from "vue";
import { Asterisk } from "lucide-vue-next";
import { watch } from "vue";
import RenderField from "../RenderField.vue";

const props = defineProps({
Expand Down Expand Up @@ -30,13 +29,6 @@ const fieldData = computed({
},
});

function handleFieldLength(event) {
if (event.key === "Enter") {
event.preventDefault();
}
event.target.style.width = (event.target.value.length + 1) * 8 + "px";
}

const getClasses = computed(() => {
switch (fieldData.value.fieldtype) {
case "Text Editor":
Expand Down Expand Up @@ -117,7 +109,7 @@ const getClasses = computed(() => {
<RenderField
:model-value="modelValue"
:field="fieldData"
@change="(value) => (modelValue = value)"
@change="(value: any) => (modelValue = value)"
:class="{ 'pointer-events-none': inEditMode }"
/>
</div>
Expand Down
50 changes: 42 additions & 8 deletions frontend/src/components/builder/sidebar/SettingsSection.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<script setup>
import { Checkbox, FormControl } from "frappe-ui";
import { Checkbox, FormControl, Tooltip } from "frappe-ui";
import { useEditForm } from "@/stores/editForm";
import { validateFormRoute } from "@/utils/form_generator";
import { ref } from "vue";
import { ref, watch } from "vue";
import { CircleCheck } from "lucide-vue-next";

const editFormStore = useEditForm();
Expand All @@ -17,6 +17,18 @@ const validateRoute = async () => {
);
showValidateMsg.value = true;
};

watch(
() => editFormStore.formData.allow_incomplete,
(newVal) => {
if (newVal) {
editFormStore.formData.login_required = true;
}
if (!newVal) {
editFormStore.formData.login_required = editFormStore.originalFormData.login_required;
}
}
);
</script>
<template>
<div class="space-y-4">
Expand Down Expand Up @@ -56,12 +68,34 @@ const validateRoute = async () => {
<CircleCheck class="w-4 h-4" /> Route is available</span
>
</div>
<Checkbox
size="sm"
label="Allow Incomplete Forms"
variant="outline"
v-model="editFormStore.formData.allow_incomplete"
/>
<Tooltip
text="Login is required when allow incomplete forms is enabled"
:disabled="!editFormStore.formData.allow_incomplete"
>
<div class="flex flex-col gap-2">
<Checkbox
v-model="editFormStore.formData.login_required"
:disabled="editFormStore.formData.allow_incomplete"
label="Login Required"
variant="outline"
size="sm"
/>
<span class="text-sm text-ink-gray-6">
If enabled, the form will require the user to login to access it.
</span>
</div>
</Tooltip>
<div class="flex flex-col gap-2">
<Checkbox
v-model="editFormStore.formData.allow_incomplete"
size="sm"
label="Allow Incomplete Forms"
variant="outline"
/>
<span class="text-sm text-ink-gray-6">
If enabled, the form will allow users to create draft submissions.
</span>
</div>
</div>
</div>
</div>
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/submission/FormHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ const submissionFormStore = useSubmissionForm();
</div>
<div v-if="submissionFormStore.formResource.data" class="flex flex-col gap-4 text-gray-800">
<h1 class="text-3xl font-bold">
{{ submissionFormStore.formResource.data?.title ?? "" }}
{{ submissionFormStore.formResource.data.title }}
</h1>
<div
v-html="submissionFormStore.formResource.data?.description"
class="form-description"
v-html="submissionFormStore.formResource.data.description"
class="form-description !px-0"
></div>
Comment on lines 11 to 18
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot Jan 2, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Find the submission form store and formResource definition
fd -e ts -e vue -e js | head -20

# Search for formResource usage
rg -n 'formResource' --type vue --type ts -B2 -A2

# Look for the API endpoints
fd -name '*.py' | xargs grep -l 'form.*resource\|frappe.whitelist'

Repository: BuildWithHussain/forms_pro

Length of output: 1241


🏁 Script executed:

# Find all Vue and TypeScript files with formResource
rg 'formResource' --type-list | head

# Search for formResource in the codebase
rg 'formResource' -B2 -A2

# Find the submission form store
fd 'store|submission' --type f | grep -E '\.(ts|js|vue)$'

# Look for API endpoints
fd '\.py$' | xargs grep -l 'form' | head -20

Repository: BuildWithHussain/forms_pro

Length of output: 17886


🏁 Script executed:

# Check the API implementation for get_form_by_route
cat frontend/src/stores/submissionForm.ts | head -50

# Look at the form.py API
cat forms_pro/api/form.py

# Check the Form doctype definition
fd 'form.json' | head -5

Repository: BuildWithHussain/forms_pro

Length of output: 5302


🏁 Script executed:

# Read the Form doctype JSON
cat forms_pro/forms_pro/doctype/form/form.json | grep -A10 -B2 '"fieldname": "title"' | head -20

# Also check for description field
cat forms_pro/forms_pro/doctype/form/form.json | grep -A10 -B2 '"fieldname": "description"' | head -20

# Get file size first to decide how to read it
wc -l forms_pro/forms_pro/doctype/form/form.json

Repository: BuildWithHussain/forms_pro

Length of output: 549


Add optional chaining for the description property.

The title field is required in the Form doctype, but description is optional. Accessing formResource.data.description directly without optional chaining will cause issues if the API returns an undefined value. Use formResource.data.description?. or add a fallback value.

🤖 Prompt for AI Agents
In frontend/src/components/submission/FormHeader.vue around lines 11 to 18, the
template binds submissionFormStore.formResource.data.description directly but
description is optional; update the v-html binding to use optional chaining or a
safe fallback (e.g.,
submissionFormStore.formResource.data.description?.toString() or
submissionFormStore.formResource.data.description ?? '') so that undefined
descriptions do not throw errors and the template renders safely.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

not required

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@harshtandiya, understood. I'll note your decision on this.

<hr />
</div>
Expand Down
42 changes: 42 additions & 0 deletions frontend/src/components/submission/PageHeader.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<script setup lang="ts">
import { Button, createResource, Popover } from "frappe-ui";
import { session } from "@/data/session";
import { useRoute } from "vue-router";
import Avatar from "../ui/Avatar.vue";

const route = useRoute();
const brandLogo = createResource({
url: "forms_pro.api.settings.get_brand_logo",
auto: true,
});
Comment on lines +8 to +11
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add error handling and loading state for brand logo.

The brand logo is rendered directly without handling loading or error states. If brandLogo.data is undefined (during loading or on error), the img tag will have a broken src attribute.

🔎 Proposed improvements
 <template>
     <div class="max-w-screen-md mx-auto flex justify-between items-center">
-        <img :src="brandLogo.data" alt="Brand Logo" class="w-10 h-10" />
+        <img 
+            v-if="brandLogo.data" 
+            :src="brandLogo.data" 
+            alt="Brand Logo" 
+            class="w-10 h-10" 
+        />
+        <div v-else class="w-10 h-10 bg-gray-200 rounded animate-pulse"></div>
         <div>

Also applies to: 19-19

🤖 Prompt for AI Agents
In frontend/src/components/submission/PageHeader.vue around lines 8-11 and line
19, the brandLogo is used directly which can produce a broken img src when
brandLogo.data is undefined; update the template to conditionally render the
<img> only when brandLogo.data is truthy, show a loading skeleton or placeholder
while brandLogo.loading is true, and render a fallback/logo text when
brandLogo.error is set; additionally add an img @error handler to swap to the
fallback source or hide the image to ensure no broken src is displayed.


function redirectToLogin() {
window.location.href = `/login?redirect-to=${route.fullPath}`;
}
Comment on lines +13 to +15
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

URL-encode the redirect path.

The route.fullPath should be URL-encoded when used as a query parameter to handle special characters correctly.

🔎 Proposed fix
 function redirectToLogin() {
-    window.location.href = `/login?redirect-to=${route.fullPath}`;
+    window.location.href = `/login?redirect-to=${encodeURIComponent(route.fullPath)}`;
 }
🤖 Prompt for AI Agents
In frontend/src/components/submission/PageHeader.vue around lines 13 to 15, the
redirect URL uses route.fullPath directly as a query value which can break with
special characters; fix by URL-encoding the path when constructing the query
(use encodeURIComponent(route.fullPath)) so the redirect-to parameter is safely
encoded before assigning window.location.href.

</script>
<template>
<div class="max-w-screen-md mx-auto flex justify-between items-center">
<img :src="brandLogo.data" alt="Brand Logo" class="w-10 h-10" />
<div>
<Popover v-if="session.user">
<template #target="{ togglePopover }">
<Button variant="ghost" @click="togglePopover">
<Avatar :userId="session.user" size="lg" />
</Button>
</template>
<template #body-main>
<div class="flex flex-col gap-2 bg-white rounded-lg p-2">
<Button
variant="ghost"
theme="red"
@click="session.logout.submit"
label="Log out"
icon-left="log-out"
/>
</div>
</template>
</Popover>
<Button v-else @click="redirectToLogin">Login</Button>
</div>
</div>
</template>
14 changes: 12 additions & 2 deletions frontend/src/pages/SubmissionPage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ import { useRoute } from "vue-router";
import { useSubmissionForm } from "@/stores/submissionForm";
import FormHeader from "@/components/submission/FormHeader.vue";
import FormRenderer from "@/components/submission/FormRenderer.vue";
import Logo from "@/assets/Logo.vue";
import PageHeader from "@/components/submission/PageHeader.vue";

const route = useRoute();
const submissionFormStore = useSubmissionForm();
submissionFormStore.initialize(route.params.route as string);
</script>
<template>
<div class="p-8">
<PageHeader />

<div
class="space-y-4 shadow-[0_0_10px_0_rgba(0,0,0,0.1)] bg-secondary border rounded-lg p-6 max-w-screen-md mx-auto mt-16"
>
Expand All @@ -21,9 +25,15 @@ submissionFormStore.initialize(route.params.route as string);
</div>

<div class="z-10 absolute bottom-0 right-0 p-8">
<div class="flex flex-col items-end text-gray-800">
<div class="flex flex-col items-end text-ink-gray-8">
<span class="text-xs">Built on</span>
<span class="font-instrument text-xl">Forms Pro</span>
<a
href="https://github.com/buildwithhussain/forms_pro"
target="_blank"
rel="noopener noreferrer"
>
<Logo class="font-normal" />
</a>
</div>
</div>
</div>
Expand Down
23 changes: 19 additions & 4 deletions frontend/src/router.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { userResource } from "@/data/user";
import { createRouter, createWebHistory } from "vue-router";
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
import { session } from "./data/session";
import { isLoginRequired } from "@/utils/form";

const routes = [
const routes: RouteRecordRaw[] = [
{
path: "/",
name: "Dashboard",
Expand All @@ -27,9 +28,19 @@ const routes = [
component: () => import("@/pages/EditForm.vue"),
},
{
path: "/p/:route",
path: "/p/:route(.*)",
name: "Form Submission Page",
component: () => import("@/pages/SubmissionPage.vue"),
meta: { allowGuest: true },
beforeEnter: async (to, from) => {
const loginRequired = await isLoginRequired(to.params.route as string);

if (loginRequired && !session.isLoggedIn) {
window.location.href = `/login?redirect-to=/forms${to.fullPath}`;
return false;
}
return true;
},
Comment thread
coderabbitai[bot] marked this conversation as resolved.
},
];

Expand All @@ -48,7 +59,11 @@ router.beforeEach(async (to, from, next) => {

if (to.name === "Login" && isLoggedIn) {
next({ name: "Home" });
} else if (to.name !== "Login" && !isLoggedIn) {
} else if (
to.name !== "Login" &&
!isLoggedIn &&
to.meta.allowGuest !== true
) {
window.location.href = `/login?redirect-to=/forms${to.fullPath}`;
} else {
next();
Expand Down
27 changes: 9 additions & 18 deletions frontend/src/stores/editForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,25 +98,16 @@ export const useEditForm = defineStore("editForm", () => {
}
});

return formResource.value.setValue.submit(
{
title: formResource.value.doc.title,
fields: formResource.value.doc.fields,
description: formResource.value.doc.description,
route: formResource.value.doc.route,
allow_incomplete: formResource.value.doc.allow_incomplete,
return formResource.value.setValue.submit(formResource.value.doc, {
onSuccess: () => {
toast.success("Form Updated Successfully");
},
{
onSuccess: () => {
toast.success("Form Updated Successfully");
},
onError: (error: any) => {
toast.error("Failed to Update Form", {
description: error.message,
});
},
}
);
onError: (error: any) => {
toast.error("Failed to Update Form", {
description: error.message,
});
},
});
}
toast.error("No form resource available");
return Promise.reject(new Error("No form resource available"));
Expand Down
Loading