Skip to content

Commit 10f98fe

Browse files
committed
feat(contact-card): add email copy functionality with feedback messages
1 parent d223395 commit 10f98fe

File tree

1 file changed

+40
-0
lines changed

1 file changed

+40
-0
lines changed

frontend/src/components/ContactCard.vue

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,21 @@
126126
>
127127
{{ mail.mail }}
128128
</a>
129+
<Button
130+
variant="ghost"
131+
size="sm"
132+
class="h-6 w-6 p-0"
133+
:disabled="isSaving"
134+
:title="'Copy email'"
135+
@click="copyEmail(mail.mail)"
136+
>
137+
<template v-if="copiedEmail === mail.mail">
138+
<CheckIcon class="w-4 h-4 text-black" />
139+
</template>
140+
<template v-else>
141+
<ClipboardIcon class="w-4 h-4" />
142+
</template>
143+
</Button>
129144
<div
130145
v-if="mail.personal || !mail.valid"
131146
class="flex gap-1 flex-shrink-0"
@@ -146,6 +161,9 @@
146161
</Badge>
147162
</div>
148163
</div>
164+
<div v-if="copyError" class="text-xs text-destructive mt-1">
165+
{{ copyError }}
166+
</div>
149167
</div>
150168
</div>
151169
</div>
@@ -255,6 +273,7 @@ import Button from "./ui/button/Button.vue";
255273
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
256274
import ContactForm from "./companies/ContactForm.vue";
257275
import type { CreateCompanyRepData } from "@/dto/companies";
276+
import { ClipboardIcon, CheckIcon } from "lucide-vue-next";
258277
259278
interface Props {
260279
contact?: Contact;
@@ -403,6 +422,27 @@ const hasSocials = (socials?: ContactSocials): boolean => {
403422
);
404423
};
405424
425+
const copiedEmail = ref<string | null>(null);
426+
const copyError = ref<string | null>(null);
427+
428+
const copyEmail = async (email: string) => {
429+
if (!navigator?.clipboard) {
430+
copyError.value = "Clipboard not available";
431+
setTimeout(() => (copyError.value = null), 2000);
432+
return;
433+
}
434+
435+
try {
436+
await navigator.clipboard.writeText(email);
437+
copiedEmail.value = email;
438+
setTimeout(() => (copiedEmail.value = null), 2000);
439+
} catch (err) {
440+
copyError.value = "Failed to copy email";
441+
setTimeout(() => (copyError.value = null), 2000);
442+
console.error("Failed to copy email:", err);
443+
}
444+
};
445+
406446
const linkedinUrl = (username: string): string => {
407447
if (username.startsWith("http")) return username;
408448
return `https://linkedin.com/in/${username}`;

0 commit comments

Comments
 (0)