158 lines
5.9 KiB
TypeScript
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>
|
|
);
|
|
}
|