ssvc-poll/src/components/admin/TokenGenerator.tsx

158 lines
5.9 KiB
TypeScript

'use client';
import { useState } from 'react';
export default function TokenGenerator() {
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const [generatedLink, setGeneratedLink] = useState<string | null>(null);
const [bulkTokenCount, setBulkTokenCount] = useState<number>(10);
const [isGeneratingBulk, setIsGeneratingBulk] = useState(false);
const handleGenerateToken = async () => {
setIsLoading(true);
setError(null);
try {
const response = await fetch('/api/generate-token', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({}), // No need to send password, using JWT cookie
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || 'Token konnte nicht generiert werden');
}
setGeneratedLink(data.voteUrl);
} catch (err) {
setError(err instanceof Error ? err.message : 'Ein Fehler ist aufgetreten');
} finally {
setIsLoading(false);
}
};
const copyToClipboard = () => {
if (generatedLink) {
navigator.clipboard.writeText(generatedLink);
alert('Link in die Zwischenablage kopiert!');
}
};
const handleGenerateBulkTokens = async () => {
setIsGeneratingBulk(true);
setError(null);
try {
// Generate the specified number of tokens
const response = await fetch('/api/generate-bulk-tokens', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ count: bulkTokenCount }),
});
if (!response.ok) {
// Try to parse error as JSON
try {
const errorData = await response.json();
throw new Error(errorData.error || 'Fehler beim Generieren der Tokens');
} catch {
// If not JSON, use status text
throw new Error(`Fehler beim Generieren der Tokens: ${response.statusText}`);
}
}
// For successful responses, get the CSV data and create a download
const csvData = await response.text();
const blob = new Blob([csvData], { type: 'text/csv;charset=utf-8;' });
const url = URL.createObjectURL(blob);
// Create a temporary link and trigger download
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', `abstimmungslinks_${new Date().toISOString().slice(0, 10)}.csv`);
document.body.appendChild(link);
link.click();
// Clean up
setTimeout(() => {
document.body.removeChild(link);
URL.revokeObjectURL(url);
}, 100);
} catch (err) {
setError(err instanceof Error ? err.message : 'Ein Fehler ist aufgetreten');
} finally {
setIsGeneratingBulk(false);
}
};
return (
<div className="mb-6">
<h2 className="text-xl font-bold text-[#0057a6] mb-4">Abstimmungslinks</h2>
<div className="flex gap-2 mb-4">
<button
onClick={handleGenerateToken}
disabled={isLoading}
className="ssvc-button flex-1 disabled:opacity-50"
>
{isLoading ? 'Generiere...' : 'Abstimmungslink generieren'}
</button>
</div>
<div className="flex gap-2 mb-4">
{generatedLink && (
<div className="mt-6 p-4 bg-[#e6f0fa] w-full">
<h3 className="font-medium text-[#0057a6] mb-2">Generierter Abstimmungslink:</h3>
<div className="break-all text-sm text-[#0057a6] mb-2">
{generatedLink}
</div>
<button
onClick={copyToClipboard}
className="w-full ssvc-button mt-2"
>
In die Zwischenablage kopieren
</button>
</div>
)}
</div>
{error && (
<div className="text-red-500 text-sm mb-4">{error}</div>
)}
<div className="mt-6 p-4">
<h3 className="font-medium text-[#0057a6] mb-2">Mehrere Abstimmungslinks generieren:</h3>
<div className="flex items-center gap-2 mb-3">
<label htmlFor="bulkTokenCount" className="text-sm">Anzahl der Links:</label>
<input
type="number"
id="bulkTokenCount"
min="1"
max="1000"
value={bulkTokenCount}
onChange={(e) => setBulkTokenCount(Math.max(1, parseInt(e.target.value) || 1))}
className="w-24 px-2 py-1 border border-gray-300 focus:outline-none focus:border-[#0057a6]"
/>
</div>
<button
onClick={handleGenerateBulkTokens}
disabled={isGeneratingBulk}
className="w-full ssvc-button disabled:opacity-50"
>
{isGeneratingBulk ? 'Generiere CSV...' : 'Links als CSV generieren'}
</button>
<p className="text-xs text-gray-600 mt-2">
Die generierten Links werden als CSV-Datei heruntergeladen, die Sie mit Ihrer Mitgliederliste zusammenführen können.
</p>
</div>
</div>
);
}