Skip to content

Commit

Permalink
chore(vue): Add custom pages and links (#4708)
Browse files Browse the repository at this point in the history
  • Loading branch information
wobsoriano authored Dec 4, 2024
1 parent 5150fa1 commit bca0e77
Show file tree
Hide file tree
Showing 12 changed files with 512 additions and 19 deletions.
5 changes: 5 additions & 0 deletions .changeset/four-beans-argue.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@clerk/vue": patch
---

Add support for custom pages and links
20 changes: 20 additions & 0 deletions integration/templates/vue-vite/src/components/CustomUserButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@ const isActionClicked = ref(false);
<div>Icon</div>
</template>
</UserButton.Link>
<UserButton.Action
label="Custom page"
open="terms"
>
<template #labelIcon>
<div>Icon</div>
</template>
</UserButton.Action>
<UserButton.Action
label="Custom action"
@click="isActionClicked = true"
Expand All @@ -27,6 +35,18 @@ const isActionClicked = ref(false);
</template>
</UserButton.Action>
</UserButton.MenuItems>
<UserButton.UserProfilePage
label="Terms"
url="terms"
>
<template #labelIcon>
<div>Icon</div>
</template>
<div>
<h1>Custom Terms Page</h1>
<p>This is the custom terms page</p>
</div>
</UserButton.UserProfilePage>
</UserButton>
<div>Is action clicked: {{ isActionClicked }}</div>
</template>
13 changes: 12 additions & 1 deletion integration/templates/vue-vite/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ const routes = [
path: '/unstyled',
component: () => import('./views/Unstyled.vue'),
},
{
name: 'CustomUserProfile',
path: '/custom-pages/user-profile',
component: () => import('./views/custom-pages/UserProfile.vue'),
},
{
name: 'CustomOrganizationProfile',
path: '/custom-pages/organization-profile',
component: () => import('./views/custom-pages/OrganizationProfile.vue'),
},
];

const router = createRouter({
Expand All @@ -35,14 +45,15 @@ const router = createRouter({

router.beforeEach(async (to, _, next) => {
const { isSignedIn, isLoaded } = useAuth();
const authenticatedPages = ['Profile', 'Admin', 'CustomUserProfile', 'CustomOrganizationProfile'];

if (!isLoaded.value) {
await waitForClerkJsLoaded(isLoaded);
}

if (isSignedIn.value && to.name === 'Sign in') {
next('/profile');
} else if (!isSignedIn.value && ['Profile', 'Admin'].includes(to.name as string)) {
} else if (!isSignedIn.value && authenticatedPages.includes(to.name)) {
next('/sign-in');
} else {
next();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<script setup lang="ts">
import { OrganizationProfile } from '@clerk/vue';
</script>

<template>
<OrganizationProfile>
<OrganizationProfile.Page
label="Terms"
url="terms"
>
<template #labelIcon>
<div>Icon</div>
</template>
<div>
<h1>Custom Terms Page</h1>
<p>This is the custom terms page</p>
</div>
</OrganizationProfile.Page>
<OrganizationProfile.Link
label="Homepage"
url="/"
>
<template #labelIcon>
<div>Icon</div>
</template>
</OrganizationProfile.Link>
<OrganizationProfile.Page label="general" />
</OrganizationProfile>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<script setup lang="ts">
import { UserProfile } from '@clerk/vue';
</script>

<template>
<UserProfile>
<UserProfile.Page
label="Terms"
url="terms"
>
<template #labelIcon>
<div>Icon</div>
</template>
<div>
<h1>Custom Terms Page</h1>
<p>This is the custom terms page</p>
</div>
</UserProfile.Page>
<UserProfile.Link
label="Homepage"
url="/"
>
<template #labelIcon>
<div>Icon</div>
</template>
</UserProfile.Link>
<UserProfile.Page label="security" />
</UserProfile>
</template>
67 changes: 66 additions & 1 deletion integration/tests/vue/components.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withCustomRoles] })('basic te
await u.po.userButton.waitForPopover();

// Check if custom menu items are visible
await u.po.userButton.toHaveVisibleMenuItems([/Custom link/i, /Custom action/i]);
await u.po.userButton.toHaveVisibleMenuItems([/Custom link/i, /Custom page/i, /Custom action/i]);

// Click custom action
await u.page.getByRole('menuitem', { name: /Custom action/i }).click();
Expand All @@ -76,6 +76,16 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withCustomRoles] })('basic te
await u.po.userButton.toggleTrigger();
await u.po.userButton.waitForPopover();

// Click custom action and check for custom page availbility
await u.page.getByRole('menuitem', { name: /Custom page/i }).click();
await u.po.userProfile.waitForUserProfileModal();
await expect(u.page.getByRole('heading', { name: 'Custom Terms Page' })).toBeVisible();

// Close the modal and trigger the popover again
await u.page.locator('.cl-modalCloseButton').click();
await u.po.userButton.toggleTrigger();
await u.po.userButton.waitForPopover();

// Click custom link and check navigation
await u.page.getByRole('menuitem', { name: /Custom link/i }).click();
await u.page.waitForAppUrl('/profile');
Expand Down Expand Up @@ -111,6 +121,61 @@ testAgainstRunningApps({ withEnv: [appConfigs.envs.withCustomRoles] })('basic te
await expect(u.page.getByText(`Hello, ${fakeUser.firstName}`)).toBeVisible();
});

test('render user profile with custom pages and links', async ({ page, context }) => {
const u = createTestUtils({ app, page, context });
await u.page.goToRelative('/sign-in');
await u.po.signIn.waitForMounted();
await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeUser.email, password: fakeUser.password });
await u.po.expect.toBeSignedIn();

await u.page.goToRelative('/custom-pages/user-profile');
await u.po.userProfile.waitForMounted();

// Check if custom pages and links are visible
await expect(u.page.getByRole('button', { name: /Terms/i })).toBeVisible();
await expect(u.page.getByRole('button', { name: /Homepage/i })).toBeVisible();

// Navigate to custom page
await u.page.getByRole('button', { name: /Terms/i }).click();
await expect(u.page.getByRole('heading', { name: 'Custom Terms Page' })).toBeVisible();

// Check reordered default label. Security tab is now the last item.
await u.page.locator('.cl-navbarButton').last().click();
await expect(u.page.getByRole('heading', { name: 'Security' })).toBeVisible();

// Click custom link and check navigation
await u.page.getByRole('button', { name: /Homepage/i }).click();
await u.page.waitForAppUrl('/');
});

test('render organization profile with custom pages and links', async ({ page, context }) => {
const u = createTestUtils({ app, page, context });
await u.page.goToRelative('/sign-in');
await u.po.signIn.waitForMounted();
await u.po.signIn.signInWithEmailAndInstantPassword({ email: fakeUser.email, password: fakeUser.password });
await u.po.expect.toBeSignedIn();

await u.page.goToRelative('/custom-pages/organization-profile');
await u.po.organizationSwitcher.waitForMounted();
await u.po.organizationSwitcher.waitForAnOrganizationToSelected();

// Check if custom pages and links are visible
await expect(u.page.getByRole('button', { name: /Terms/i })).toBeVisible();
await expect(u.page.getByRole('button', { name: /Homepage/i })).toBeVisible();

// Navigate to custom page
await u.page.getByRole('button', { name: /Terms/i }).click();
await expect(u.page.getByRole('heading', { name: 'Custom Terms Page' })).toBeVisible();

// Check reordered default label. General tab is now the last item.
await u.page.locator('.cl-navbarButton').last().click();
await expect(u.page.getByRole('heading', { name: 'General' })).toBeVisible();

// Click custom link and check navigation
await u.page.getByRole('button', { name: /Homepage/i }).click();
await u.page.waitForAppUrl('/');
});

test('redirects to sign-in when unauthenticated', async ({ page, context }) => {
const u = createTestUtils({ app, page, context });
await u.page.goToRelative('/profile');
Expand Down
Loading

0 comments on commit bca0e77

Please sign in to comment.