Initial working commit
Some checks failed
Automated Container Build / build-and-push (push) Failing after 7s

This commit is contained in:
Elijah 2026-06-27 19:19:38 -07:00
parent 666ceb7325
commit b7ce314f01
105 changed files with 35510 additions and 11 deletions

View file

@ -0,0 +1,121 @@
"use client";
import { useState, useEffect } from "react";
interface ShareMenuProps {
targetType: "DECK" | "QUIZ";
contentId: string;
classSlug: string;
}
export function ShareMenu({ targetType, contentId, classSlug }: ShareMenuProps) {
const [token, setToken] = useState<string | null>(null);
const [loading, setLoading] = useState(true);
const [open, setOpen] = useState(false);
const [copied, setCopied] = useState(false);
useEffect(() => {
if (!open) return;
fetch(`/api/share?targetType=${targetType}&contentId=${contentId}`)
.then(res => res.json())
.then(data => setToken(data.token))
.finally(() => setLoading(false));
}, [open, targetType, contentId]);
async function handleToggle() {
setLoading(true);
try {
const res = await fetch("/api/share", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ targetType, contentId }),
});
const data = await res.json();
setToken(data.token);
} finally {
setLoading(false);
}
}
async function handleCopy() {
if (!token) return;
const typeStr = targetType === "DECK" ? "flashcards" : "quizzes";
const url = `${window.location.origin}/shared/${classSlug}/${typeStr}/${token}`;
await navigator.clipboard.writeText(url);
setCopied(true);
setTimeout(() => setCopied(false), 2000);
}
return (
<div className="relative">
<button
onClick={() => setOpen(!open)}
className="p-2 rounded-lg text-text-muted hover:text-text-heading hover:bg-bg-surface-alt transition-all duration-200 cursor-pointer"
title="Share"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8.684 13.342C8.886 12.938 9 12.482 9 12c0-.482-.114-.938-.316-1.342m0 2.684a3 3 0 110-2.684m0 2.684l6.632 3.316m-6.632-6l6.632-3.316m0 0a3 3 0 105.367-2.684 3 3 0 00-5.367 2.684zm0 9.316a3 3 0 105.368 2.684 3 3 0 00-5.368-2.684z" />
</svg>
</button>
{open && (
<>
<div className="fixed inset-0 z-40" onClick={() => setOpen(false)} />
<div className="absolute right-0 mt-2 w-72 bg-bg-surface rounded-xl shadow-[var(--shadow-modal)] border border-border-light z-50 p-4 animate-slide-up origin-top-right">
<h4 className="text-sm font-semibold text-text-heading mb-3">Public Sharing</h4>
{loading ? (
<div className="h-8 bg-bg-surface-alt rounded w-full animate-subtle-pulse" />
) : (
<div className="space-y-4">
<div className="flex items-center justify-between">
<span className="text-sm text-text-secondary">Enable link sharing</span>
<button
onClick={handleToggle}
className={`relative inline-flex h-5 w-9 items-center rounded-full transition-colors ${
token ? 'bg-primary' : 'bg-border'
}`}
>
<span
className={`inline-block h-3 w-3 transform rounded-full bg-white transition-transform ${
token ? 'translate-x-5' : 'translate-x-1'
}`}
/>
</button>
</div>
{token && (
<div className="space-y-2 pt-2 border-t border-border-light">
<p className="text-xs text-text-muted">
Anyone with the link can view and study this {targetType === "DECK" ? "deck" : "quiz"}. No progress is saved.
</p>
<button
onClick={handleCopy}
className="w-full flex items-center justify-center gap-2 py-2 px-3 rounded-lg border border-primary text-primary hover:bg-primary/5 transition-colors text-sm font-medium cursor-pointer"
>
{copied ? (
<>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
</svg>
Copied to Clipboard
</>
) : (
<>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" />
</svg>
Copy Link
</>
)}
</button>
</div>
)}
</div>
)}
</div>
</>
)}
</div>
);
}