Skip to content
Open
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
39 changes: 39 additions & 0 deletions lego-webapp/components/ShareButton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Button, Flex, Icon } from '@webkom/lego-bricks';
import { Share2, ShareIcon } from 'lucide-react';
import { useAppDispatch } from 'lego-webapp/redux/hooks';
import { addToast } from '~/redux/slices/toasts';

type Props = {
title: string;
url: string;
};

const ShareButton: React.FC<Props> = ({ title, url }) => {
const dispatch = useAppDispatch();
const handleShare = async () => {
if (navigator?.canShare?.({ title, url })) {
navigator.share({ title, url });
Comment on lines +14 to +15
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Consider browser compatibility for Web Share API.

While you're correctly checking for navigator.canShare support, some browsers might partially implement the API but have limitations. Consider adding a fallback for unsupported share data types.


🌐 Web query:

Which browsers support the Web Share API and what are their limitations?

💡 Result:

The Web Share API is supported across most modern browsers, but with varying levels of compatibility and limitations. Here's a detailed breakdown:

Browser Support

  • Chrome:

    • ✅ Full support: v89+ (desktop), all versions (Android)
    • ◐ Partial support: v89–v131 (desktop)
    • ❌ No support: v4–v88 [1][4]
  • Edge:

    • ✅ Full support: v95+
    • ◐ Partial support: v81–94
    • ❌ No support: v12–80 [1][4][10]
  • Safari:

    • ✅ Full support: v12.1+ (macOS), v12.2+ (iOS)
    • ❌ No support: older versions [1][4][7]
  • Opera:

    • ✅ Full support: v114+ (desktop), v72–80 (Mobile)
    • ❌ No support: v9.5–113 [1][4]
  • Mobile Browsers:

    • Chrome for Android: All versions
    • Firefox for Android: All versions
    • Samsung Internet: v8.2+ [1][4]
Browser Desktop Support Mobile Support
Chrome v89+ (partial/full) All versions (full)
Edge v95+ (full) Not specified
Safari v12.1+ (macOS) v12.2+ (iOS)
Firefox ✅ All (Android)
Opera v114+ (full) v72–80 (Mobile)

Key Limitations

  1. Secure Context Requirement:

    • Requires HTTPS in production. Localhost/testing environments may not work unless using tools like JSFiddle [3][7][10].
  2. Desktop Browser Gaps:

    • Poor desktop support except Chrome and Edge (partial/full). Firefox desktop lacks support entirely [3][4][7].
  3. User Interaction Dependency:

    • Must be triggered by transient activation (e.g., button click). Background/script-initiated sharing fails [8][10].
  4. Variable Share Targets:

    • Available apps depend on the OS/device. Developers can’t customize the list or track which app was used [3][7].
  5. Third-Party Iframe Restrictions:

    • Embedded iframes need explicit permissions via <iframe allow="web-share">. Otherwise, NotAllowedError occurs [5][6].
  6. File Sharing Constraints:

    • Requires validation via navigator.canShare({ files }) first. Large files or unsupported types may fail silently [7][12].

For unsupported browsers (e.g., Firefox desktop), developers must implement fallback sharing UIs. Compatibility checks with navigator.canShare() are recommended before invoking the API [7][10].

Citations:


Web Share API: Enhance Fallbacks for Partial & Unsupported Environments

In lego-webapp/components/ShareButton/index.tsx (lines 14–15), you’re correctly checking for the existence of navigator?.canShare before calling navigator.share. However, as our latest research indicates, browser support for the Web Share API is nuanced:

  • Variability Across Browsers:

    • Chrome & Edge: Generally provide full or partial support, though you might encounter differences based on the version.
    • Safari: Supports the API on modern macOS and iOS versions.
    • Firefox Desktop: Does not support the API at all, so users on Firefox will not be able to share via this mechanism.
  • Limitations & Fallback Needs:

    • Even when navigator.canShare is available, certain share data types (especially files) may not be fully supported.
    • The API requires a secure context (HTTPS) and user interaction, which might not cover all scenarios.
    • A fallback mechanism—such as a copy-to-clipboard for URLs or a custom sharing modal—can help address these discrepancies and improve the user experience in unsupported or partially supported environments.

Please consider implementing a graceful fallback for cases where the API’s capabilities are limited or absent. This will ensure a more consistent sharing experience across all browsers.

} else {
{
navigator.clipboard.writeText(url);
}
dispatch(
addToast({
message: 'Link er kopiert til utklippstavlen',
type: 'success',
}),
);
}
};
Comment on lines +13 to +27
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

Fix unnecessary block statement and add error handling.

The share functionality works as expected, but there's an unnecessary block statement and error handling should be added for clipboard and share operations.

const handleShare = async () => {
  if (navigator?.canShare?.({ title, url })) {
-    navigator.share({ title, url });
+    try {
+      await navigator.share({ title, url });
+    } catch (error) {
+      console.error('Error sharing:', error);
+      await copyToClipboard();
+    }
  } else {
-    {
-      navigator.clipboard.writeText(url);
-    }
-    dispatch(
-      addToast({
-        message: 'Link er kopiert til utklippstavlen',
-        type: 'success',
-      }),
-    );
+    await copyToClipboard();
+  }
+};
+
+const copyToClipboard = async () => {
+  try {
+    await navigator.clipboard.writeText(url);
+    dispatch(
+      addToast({
+        message: 'Link er kopiert til utklippstavlen',
+        type: 'success',
+      }),
+    );
+  } catch (error) {
+    console.error('Error copying to clipboard:', error);
+    dispatch(
+      addToast({
+        message: 'Kunne ikke kopiere link',
+        type: 'error',
+      }),
+    );
  }
};
📝 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
const handleShare = async () => {
if (navigator?.canShare?.({ title, url })) {
navigator.share({ title, url });
} else {
{
navigator.clipboard.writeText(url);
}
dispatch(
addToast({
message: 'Link er kopiert til utklippstavlen',
type: 'success',
}),
);
}
};
const handleShare = async () => {
if (navigator?.canShare?.({ title, url })) {
try {
await navigator.share({ title, url });
} catch (error) {
console.error('Error sharing:', error);
await copyToClipboard();
}
} else {
await copyToClipboard();
}
};
const copyToClipboard = async () => {
try {
await navigator.clipboard.writeText(url);
dispatch(
addToast({
message: 'Link er kopiert til utklippstavlen',
type: 'success',
}),
);
} catch (error) {
console.error('Error copying to clipboard:', error);
dispatch(
addToast({
message: 'Kunne ikke kopiere link',
type: 'error',
}),
);
}
};
🧰 Tools
🪛 Biome (1.9.4)

[error] 17-19: This block statement doesn't serve any purpose and can be safely removed.

Standalone block statements without any block-level declarations are redundant in JavaScript and can be removed to simplify the code.
Safe fix: Remove redundant block.

(lint/complexity/noUselessLoneBlockStatements)


return (
<Button onPress={handleShare}>
<Flex justifyContent="center" gap="var(--spacing-sm)">
<Icon iconNode={<ShareIcon />} size={20} />
{title}
</Flex>
</Button>
);
};

export default ShareButton;
8 changes: 8 additions & 0 deletions lego-webapp/pages/events/@eventIdOrSlug/+Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import DisplayContent from '~/components/DisplayContent';
import InfoList from '~/components/InfoList';
import { mazemapScript } from '~/components/MazemapEmbed';
import PropertyHelmet from '~/components/PropertyHelmet';
import ShareButton from '~/components/ShareButton';
import Tag from '~/components/Tags/Tag';
import TextWithIcon from '~/components/TextWithIcon';
import {
Expand Down Expand Up @@ -306,6 +307,13 @@ const EventDetail = () => {
/>
)}

<Line />

<ShareButton
title={'Del arrangement'}
url={`${appConfig?.webUrl}/events/${event?.id}`}
/>

{(actionGrant.includes('edit') || actionGrant.includes('delete')) && (
<Line />
)}
Expand Down
6 changes: 6 additions & 0 deletions lego-webapp/pages/joblistings/@joblistingIdOrSlug/+Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import DisplayContent from '~/components/DisplayContent';
import InfoList from '~/components/InfoList';
import { jobType, Year, Workplaces } from '~/components/JoblistingItem/Items';
import PropertyHelmet from '~/components/PropertyHelmet';
import ShareButton from '~/components/ShareButton';
import Time from '~/components/Time';
import YoutubeCover from '~/pages/pages/_components/YoutubeCover';
import { fetchJoblisting } from '~/redux/actions/JoblistingActions';
Expand Down Expand Up @@ -236,6 +237,11 @@ const JoblistingDetail = () => {
</div>
)}

<ShareButton
title={'Del jobbannonse'}
url={`${appConfig?.webUrl}/joblistings/${joblisting?.id}`}
/>

{(canEdit || canDelete) && (
<div>
<h3>Admin</h3>
Expand Down