Skip to content

Vanity urls#493

Open
Sam Beveridge (00salmon) wants to merge 14 commits intomasterfrom
vanity-url
Open

Vanity urls#493
Sam Beveridge (00salmon) wants to merge 14 commits intomasterfrom
vanity-url

Conversation

@00salmon
Copy link
Copy Markdown
Contributor

Description of the change

Description here

Type of change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation or Development tools (readme, specs, tests, code formatting)

Links

  • Jira issue number: (PUT IT HERE)
  • Process.st launch checklist: (PUT IT HERE)

Checklists

Development

  • Prettier was run (if applicable)
  • The behaviour changes in the pull request are covered by specs
  • All tests related to the changed code pass in development

Paperwork

  • This pull request has a descriptive title and information useful to a reviewer
  • This pull request has a Jira number
  • This pull request has a Process.st launch checklist

Code review

  • Changes have been reviewed by at least one other engineer
  • Security impacts of this change have been considered

Copilot AI review requested due to automatic review settings April 16, 2026 21:50
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces “vanity URL” customization support for the sqm-share-link component, adding UI and GraphQL operations to validate and save user-chosen link codes.

Changes:

  • Adds a new ShareLinkView with an edit mode UI (validation, save/cancel, edit-limit messaging).
  • Extends useShareLink to support vanity link validation/saving and edit limit tracking via new GraphQL queries/mutations.
  • Updates documentation, Storybook stories, and dependency graphs to reflect the new component relationships.

Reviewed changes

Copilot reviewed 11 out of 13 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
packages/mint-components/src/index.html Adds a commented-out example usage for sqm-share-link.
packages/mint-components/src/components/sqm-stencilbook/readme.md Updates the component dependency graph to include sqm-share-link.
packages/mint-components/src/components/sqm-share-link/useShareLink.tsx Implements vanity link customization logic, validation debounce, and new GraphQL operations.
packages/mint-components/src/components/sqm-share-link/sqm-share-link.tsx Adds new props for vanity customization and switches rendering to ShareLinkView.
packages/mint-components/src/components/sqm-share-link/sqm-share-link-view.tsx New view implementing the customization/edit UI and edit-limit message rendering.
packages/mint-components/src/components/sqm-share-link/readme.md Documents new props and dependency graph updates.
packages/mint-components/src/components/sqm-share-link/UseShareLink.stories.tsx Updates hook stories to use ShareLinkView and adds a customization-enabled story.
packages/mint-components/src/components/sqm-share-link/ShareLink.stories.tsx Adds multiple ShareLinkView stories covering customization states.
packages/mint-components/src/components/sqm-share-code/sqm-share-code.tsx Removes a now-irrelevant rewardStatus field in demo props and formats options.
packages/mint-components/src/components/sqm-form-message/readme.md Updates docs dependency listing/graph to include sqm-share-link.
packages/mint-components/src/components.d.ts Updates generated typings to include the new props and demo data type for sqm-share-link.
packages/mint-components/package.json Bumps package version and updates @raisins/stencil-docs-target dependency.
packages/mint-components/package-lock.json Updates lockfile for the dependency bump (but version metadata is currently inconsistent).
Files not reviewed (1)
  • packages/mint-components/package-lock.json: Language not supported

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

import { isDemo } from "@saasquatch/component-boilerplate";
import { useState, withHooks } from "@saasquatch/stencil-hooks";
import { Component, Prop, h } from "@stencil/core";
import { Component, Fragment, Prop, h } from "@stencil/core";
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

Fragment is imported from @stencil/core but not used in this file. Remove the unused import to keep the module clean.

Suggested change
import { Component, Fragment, Prop, h } from "@stencil/core";
import { Component, Prop, h } from "@stencil/core";

Copilot uses AI. Check for mistakes.
Comment on lines 1 to 10
{
"name": "@saasquatch/mint-components",
"version": "2.1.7",
"version": "2.1.8-18",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@saasquatch/mint-components",
"version": "2.1.7",
"version": "2.1.8-18",
"hasInstallScript": true,
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

package-lock.json version is 2.1.8-18 (both the top-level and the packages[""] entry), but package.json was bumped to 2.1.8-19. Update the lockfile version fields so they match the package version to avoid inconsistent dependency metadata.

Copilot uses AI. Check for mistakes.
Comment on lines 58 to 63
const MessageLinkQuery = gql`
query ($programId: ID, $engagementMedium: UserEngagementMedium!) {
query ($programId: ID) {
user: viewer {
... on User {
shareLink(
programId: $programId
engagementMedium: $engagementMedium
shareMedium: DIRECT
)
shareLink(programId: $programId)
}
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

shareLink GraphQL query here no longer passes engagementMedium (and previously also passed shareMedium: DIRECT). Other components in this repo still query shareLink with engagementMedium: UserEngagementMedium! (e.g. sqm-qr-code/useQRCode.ts), so this change is likely to cause a runtime GraphQL validation error or change link generation semantics. Restore the required arguments/variables (or update all shareLink queries consistently if the schema changed).

Copilot uses AI. Check for mistakes.
tooltiplifespan: number;
linkOverride?: string;
customizeUrl?: boolean;
customizeUrlText?: string;
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

customizeUrlText is declared on ShareLinkProps but never used anywhere in the hook or view. If it’s not needed, remove it; if it’s meant to control UI copy, thread it through to ShareLinkView and document it in sqm-share-link/readme.md.

Suggested change
customizeUrlText?: string;

Copilot uses AI. Check for mistakes.
Comment on lines +267 to +287
if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current);

if (!trimmed || trimmed.length < MIN_CHARACTERS) {
setIsValidating(false);
return;
}

setIsValidating(true);
debounceTimerRef.current = setTimeout(async () => {
try {
const result = await validateLinkCode({ linkCode: trimmed });
if (!result?.validateLinkCode?.valid) {
const reason = result?.validateLinkCode
?.invalidReason as ValidationErrorCode;
setValidationError(mapErrorCodeToInfo(reason));
}
} catch {
// Validation query failed — don't block the user
}
setIsValidating(false);
}, 2000);
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

The debounced validation uses a setTimeout but the timer is only cleared when the input changes. If the user cancels/saves (or the component unmounts) while a timer is pending, the callback can still run later and update state, potentially reintroducing validation errors after leaving edit mode. Clear any pending timer on cancel/save and on unmount (cleanup effect), and consider guarding against stale async responses updating state for an older trimmed value.

Copilot uses AI. Check for mistakes.
Comment on lines +298 to +301
supportLink: (
<a target="_blank" href="https://example.com">
{supportLinkText}
</a>
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

The support link in the edit-limit message is hard-coded to https://example.com, which will ship users to a placeholder domain and isn’t configurable via props. Consider adding a supportLinkUrl/supportEmail prop (similar to other components) or otherwise sourcing the real destination. Also, since this uses target="_blank", add rel="noopener noreferrer" to prevent reverse-tabnabbing.

Copilot uses AI. Check for mistakes.
Comment on lines 3 to 5
"title": "Mint Components",
"version": "2.1.7",
"version": "2.1.8-19",
"description": "A minimal design library with components for referral and loyalty experiences. Built with Shoelace components by Saasquatch.",
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

package.json sets the package version to 2.1.8-19, but package-lock.json was updated to 2.1.8-18. This mismatch can cause confusing installs/publishes; align the version fields across both files (and the nested packages[""] entry in the lockfile).

Copilot uses AI. Check for mistakes.
Comment on lines +326 to +331
function onCancel() {
setIsEditing(false);
setEditValue("");
setValidationError(null);
setIsValidating(false);
}
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

onCancel resets editing state but does not clear any pending debounce timer started by onEditValueChange. This can cause setValidationError/setIsValidating to run after cancel, leaving stale validation state the next time the editor is opened. Clear the pending timeout in onCancel (and similarly after a successful save).

Copilot uses AI. Check for mistakes.
Comment on lines +243 to +256
<button
class={sheet.classes.SaveButton}
onClick={onSave}
disabled={
isSaving || isValidating || !!validationError || !editValue || editValue.length < minCharacters
}
>
{isSaving ? "Saving..." : saveLabelText}
</button>
<button
class={sheet.classes.CancelButton}
onClick={onCancel}
disabled={isSaving}
>
Copy link

Copilot AI Apr 16, 2026

Choose a reason for hiding this comment

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

The Save/Cancel controls are plain <button> elements without an explicit type. If this component is ever rendered inside a form, these will default to type="submit" and may trigger unintended form submission. Set type="button" on both buttons (and keep disabled behavior as-is).

Copilot uses AI. Check for mistakes.
>
{isSaving ? "Saving..." : saveLabelText}
</button>
<button
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is it possible to use shoelace components in the editing state?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants