📦 EqualifyEverything / equalify

📄 ShareModal.tsx · 71 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71import { useState } from "react";
import * as Dialog from "@radix-ui/react-dialog";
import { FaClipboard, FaCheckCircle } from "react-icons/fa";
import { StyledButton } from "./StyledButton";
import styles from "./ShareModal.module.scss";

interface ShareModalProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  shareUrl: string;
}

export const ShareModal = ({ open, onOpenChange, shareUrl }: ShareModalProps) => {
  const [copied, setCopied] = useState(false);

  const copyToClipboard = async () => {
    try {
      await navigator.clipboard.writeText(shareUrl);
      setCopied(true);
      setTimeout(() => setCopied(false), 2500);
    } catch (err) {
      console.error("Failed to copy share URL:", err);
    }
  };

  return (
    <Dialog.Root open={open} onOpenChange={onOpenChange}>
      <Dialog.Portal>
        <Dialog.Overlay className={styles.overlay} />
        <Dialog.Content className={styles.content}>
          <Dialog.Title className={styles.title}>Share Report</Dialog.Title>
          <Dialog.Description className={styles.description}>
            Anyone with this link can view this accessibility report — no login required.
          </Dialog.Description>

          <div className={styles["url-row"]}>
            <label htmlFor="share-modal-url" className="sr-only">
              Shareable link
            </label>
            <input
              id="share-modal-url"
              type="text"
              readOnly
              value={shareUrl}
              onFocus={(e) => e.target.select()}
              onClick={(e) => (e.target as HTMLInputElement).select()}
            />
            <StyledButton
              onClick={copyToClipboard}
              label={copied ? "Copied!" : "Copy link"}
              icon={copied ? <FaCheckCircle /> : <FaClipboard />}
              variant={copied ? "green" : "dark"}
            />
          </div>

          {/* Announced to screen readers when copy succeeds */}
          <div role="status" aria-live="polite" aria-atomic="true" className="sr-only">
            {copied ? "Link copied to clipboard." : ""}
          </div>

          <Dialog.Close asChild>
            <button className={styles["close-button"]} aria-label="Close share dialog">
              ×
            </button>
          </Dialog.Close>
        </Dialog.Content>
      </Dialog.Portal>
    </Dialog.Root>
  );
};