Implement local browser caching for shared groups and UI improvements
All checks were successful
Automated Container Build / build-and-push (push) Successful in 1m10s
All checks were successful
Automated Container Build / build-and-push (push) Successful in 1m10s
This commit is contained in:
parent
42ed0d275b
commit
7af0935657
37 changed files with 6141 additions and 411 deletions
|
|
@ -3,7 +3,7 @@
|
|||
import { useState, useEffect } from "react";
|
||||
|
||||
interface ShareMenuProps {
|
||||
targetType: "DECK" | "QUIZ";
|
||||
targetType: "DECK" | "QUIZ" | "GROUP";
|
||||
contentId: string;
|
||||
classSlug: string;
|
||||
}
|
||||
|
|
@ -13,12 +13,18 @@ export function ShareMenu({ targetType, contentId, classSlug }: ShareMenuProps)
|
|||
const [loading, setLoading] = useState(true);
|
||||
const [open, setOpen] = useState(false);
|
||||
const [copied, setCopied] = useState(false);
|
||||
const [isGroupShared, setIsGroupShared] = useState(false);
|
||||
const [groupName, setGroupName] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return;
|
||||
fetch(`/api/share?targetType=${targetType}&contentId=${contentId}`)
|
||||
.then(res => res.json())
|
||||
.then(data => setToken(data.token))
|
||||
.then(data => {
|
||||
setToken(data.token);
|
||||
setIsGroupShared(data.isGroupShared || false);
|
||||
setGroupName(data.groupName || null);
|
||||
})
|
||||
.finally(() => setLoading(false));
|
||||
}, [open, targetType, contentId]);
|
||||
|
||||
|
|
@ -39,7 +45,7 @@ export function ShareMenu({ targetType, contentId, classSlug }: ShareMenuProps)
|
|||
|
||||
async function handleCopy() {
|
||||
if (!token) return;
|
||||
const typeStr = targetType === "DECK" ? "flashcards" : "quizzes";
|
||||
const typeStr = targetType === "GROUP" ? "groups" : (targetType === "DECK" ? "flashcards" : "quizzes");
|
||||
const url = `${window.location.origin}/shared/${classSlug}/${typeStr}/${token}`;
|
||||
await navigator.clipboard.writeText(url);
|
||||
setCopied(true);
|
||||
|
|
@ -72,22 +78,29 @@ export function ShareMenu({ targetType, contentId, classSlug }: ShareMenuProps)
|
|||
<span className="text-sm text-text-secondary">Enable link sharing</span>
|
||||
<button
|
||||
onClick={handleToggle}
|
||||
disabled={isGroupShared}
|
||||
className={`relative inline-flex h-5 w-9 items-center rounded-full transition-colors ${
|
||||
token ? 'bg-primary' : 'bg-border'
|
||||
}`}
|
||||
token || isGroupShared ? 'bg-primary' : 'bg-border'
|
||||
} ${isGroupShared ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}`}
|
||||
>
|
||||
<span
|
||||
className={`inline-block h-3 w-3 transform rounded-full bg-white transition-transform ${
|
||||
token ? 'translate-x-5' : 'translate-x-1'
|
||||
token || isGroupShared ? 'translate-x-5' : 'translate-x-1'
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{isGroupShared && (
|
||||
<div className="text-xs text-primary font-medium px-3 py-2 bg-primary/10 rounded-lg">
|
||||
This item is publicly shared via its group: <span className="font-bold">{groupName}</span>. Turn off group sharing to restrict access.
|
||||
</div>
|
||||
)}
|
||||
|
||||
{token && (
|
||||
{(token || isGroupShared) && (
|
||||
<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.
|
||||
Anyone with the link can view and study this {targetType === "GROUP" ? "group" : (targetType === "DECK" ? "deck" : "quiz")}. No progress is saved.
|
||||
</p>
|
||||
<button
|
||||
onClick={handleCopy}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue