diff --git a/packages/twenty-front/src/hooks/useCopyToClipboard.tsx b/packages/twenty-front/src/hooks/useCopyToClipboard.tsx
index 182fd0ce18..22ee1cbec9 100644
--- a/packages/twenty-front/src/hooks/useCopyToClipboard.tsx
+++ b/packages/twenty-front/src/hooks/useCopyToClipboard.tsx
@@ -9,6 +9,18 @@ export const useCopyToClipboard = () => {
const { t } = useLingui();
const copyToClipboard = async (valueAsString: string, message?: string) => {
+ if (!window.isSecureContext) {
+ enqueueErrorSnackBar({
+ message: t`Clipboard requires a secure connection (HTTPS). Please access this app over HTTPS to enable copying.`,
+ options: {
+ icon: ,
+ duration: 6000,
+ },
+ });
+
+ return;
+ }
+
try {
await navigator.clipboard.writeText(valueAsString);
diff --git a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpTwoFactorAuthenticationProvision.tsx b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpTwoFactorAuthenticationProvision.tsx
index 487dd69854..532c83ebf5 100644
--- a/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpTwoFactorAuthenticationProvision.tsx
+++ b/packages/twenty-front/src/modules/auth/sign-in-up/components/internal/SignInUpTwoFactorAuthenticationProvision.tsx
@@ -5,7 +5,6 @@ import {
signInUpStepState,
} from '@/auth/states/signInUpStepState';
import { extractSecretFromOtpUri } from '@/settings/two-factor-authentication/utils/extractSecretFromOtpUri';
-import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import { Trans, useLingui } from '@lingui/react/macro';
@@ -15,6 +14,7 @@ import { IconCopy } from 'twenty-ui/display';
import { Loader } from 'twenty-ui/feedback';
import { MainButton } from 'twenty-ui/input';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
+import { useCopyToClipboard } from '~/hooks/useCopyToClipboard';
const StyledMainContentContainer = styled.div`
margin-bottom: ${({ theme }) => theme.spacing(8)};
@@ -69,7 +69,7 @@ const StyledCopySetupKeyLink = styled.button`
export const SignInUpTwoFactorAuthenticationProvision = () => {
const { t } = useLingui();
const theme = useTheme();
- const { enqueueSuccessSnackBar } = useSnackBar();
+ const { copyToClipboard } = useCopyToClipboard();
const qrCode = useRecoilValueV2(qrCodeState);
const setSignInUpStep = useSetRecoilState(signInUpStepState);
@@ -82,14 +82,7 @@ export const SignInUpTwoFactorAuthenticationProvision = () => {
const secret = extractSecretFromOtpUri(qrCode);
if (secret !== null) {
- await navigator.clipboard.writeText(secret);
- enqueueSuccessSnackBar({
- message: t`Setup key copied to clipboard`,
- options: {
- icon: ,
- duration: 2000,
- },
- });
+ await copyToClipboard(secret, t`Setup key copied to clipboard`);
}
};
diff --git a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownVisibilityContent.tsx b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownVisibilityContent.tsx
index 1a8404d0f0..4bea9240ce 100644
--- a/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownVisibilityContent.tsx
+++ b/packages/twenty-front/src/modules/object-record/object-options-dropdown/components/ObjectOptionsDropdownVisibilityContent.tsx
@@ -1,7 +1,6 @@
import { OBJECT_OPTIONS_DROPDOWN_ID } from '@/object-record/object-options-dropdown/constants/ObjectOptionsDropdownId';
import { useObjectOptionsDropdown } from '@/object-record/object-options-dropdown/hooks/useObjectOptionsDropdown';
import { useHasPermissionFlag } from '@/settings/roles/hooks/useHasPermissionFlag';
-import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { DropdownContent } from '@/ui/layout/dropdown/components/DropdownContent';
import { DropdownMenuHeader } from '@/ui/layout/dropdown/components/DropdownMenuHeader/DropdownMenuHeader';
import { DropdownMenuHeaderLeftComponent } from '@/ui/layout/dropdown/components/DropdownMenuHeader/internal/DropdownMenuHeaderLeftComponent';
@@ -15,7 +14,6 @@ import { useRecoilComponentValue } from '@/ui/utilities/state/component-state/ho
import { useCanPersistViewChanges } from '@/views/hooks/useCanPersistViewChanges';
import { useGetCurrentViewOnly } from '@/views/hooks/useGetCurrentViewOnly';
import { useUpdateCurrentView } from '@/views/hooks/useUpdateCurrentView';
-import { useTheme } from '@emotion/react';
import { useLingui } from '@lingui/react/macro';
import { createPortal } from 'react-dom';
import {
@@ -30,14 +28,14 @@ import {
ViewVisibility,
PermissionFlagType,
} from '~/generated-metadata/graphql';
+import { useCopyToClipboard } from '~/hooks/useCopyToClipboard';
export const ObjectOptionsDropdownVisibilityContent = () => {
const { t } = useLingui();
- const theme = useTheme();
const { resetContent } = useObjectOptionsDropdown();
const { currentView } = useGetCurrentViewOnly();
const { updateCurrentView } = useUpdateCurrentView();
- const { enqueueSuccessSnackBar } = useSnackBar();
+ const { copyToClipboard } = useCopyToClipboard();
const hasViewsPermission = useHasPermissionFlag(PermissionFlagType.VIEWS);
const { canPersistChanges } = useCanPersistViewChanges();
@@ -59,16 +57,9 @@ export const ObjectOptionsDropdownVisibilityContent = () => {
resetContent();
};
- const handleCopyLink = () => {
+ const handleCopyLink = async () => {
const currentUrl = window.location.href;
- navigator.clipboard.writeText(currentUrl);
- enqueueSuccessSnackBar({
- message: t`Link copied to clipboard`,
- options: {
- icon: ,
- duration: 2000,
- },
- });
+ await copyToClipboard(currentUrl, t`Link copied to clipboard`);
};
const currentVisibility = currentView?.visibility ?? ViewVisibility.WORKSPACE;
diff --git a/packages/twenty-front/src/pages/settings/SettingsTwoFactorAuthenticationMethod.tsx b/packages/twenty-front/src/pages/settings/SettingsTwoFactorAuthenticationMethod.tsx
index 10009f69d4..1f34939127 100644
--- a/packages/twenty-front/src/pages/settings/SettingsTwoFactorAuthenticationMethod.tsx
+++ b/packages/twenty-front/src/pages/settings/SettingsTwoFactorAuthenticationMethod.tsx
@@ -12,15 +12,14 @@ import { TwoFactorAuthenticationVerificationForSettings } from '@/settings/two-f
import { useCurrentUserWorkspaceTwoFactorAuthentication } from '@/settings/two-factor-authentication/hooks/useCurrentUserWorkspaceTwoFactorAuthentication';
import { useTwoFactorVerificationForSettings } from '@/settings/two-factor-authentication/hooks/useTwoFactorVerificationForSettings';
import { extractSecretFromOtpUri } from '@/settings/two-factor-authentication/utils/extractSecretFromOtpUri';
-import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { SubMenuTopBarContainer } from '@/ui/layout/page/components/SubMenuTopBarContainer';
-import { useTheme } from '@emotion/react';
import { SettingsPath } from 'twenty-shared/types';
import { getSettingsPath } from 'twenty-shared/utils';
-import { H2Title, IconCopy } from 'twenty-ui/display';
+import { H2Title } from 'twenty-ui/display';
import { Loader } from 'twenty-ui/feedback';
import { Section } from 'twenty-ui/layout';
import { useRecoilValueV2 } from '@/ui/utilities/state/jotai/hooks/useRecoilValueV2';
+import { useCopyToClipboard } from '~/hooks/useCopyToClipboard';
const StyledQRCodeContainer = styled.div`
margin: ${({ theme }) => theme.spacing(4)} 0;
@@ -79,8 +78,7 @@ const StyledDivider = styled.div`
export const SettingsTwoFactorAuthenticationMethod = () => {
const { t } = useLingui();
- const theme = useTheme();
- const { enqueueSuccessSnackBar } = useSnackBar();
+ const { copyToClipboard } = useCopyToClipboard();
const qrCode = useRecoilValueV2(qrCodeState);
const { currentUserWorkspaceTwoFactorAuthenticationMethods } =
@@ -99,14 +97,7 @@ export const SettingsTwoFactorAuthenticationMethod = () => {
const secret = extractSecretFromOtpUri(qrCode);
if (secret !== null) {
- await navigator.clipboard.writeText(secret);
- enqueueSuccessSnackBar({
- message: t`Setup key copied to clipboard`,
- options: {
- icon: ,
- duration: 2000,
- },
- });
+ await copyToClipboard(secret, t`Setup key copied to clipboard`);
}
};