- Add slug/short_id fields to database with auto-generation

- Create migration script for existing data
- Update admin interface to show only short URLs
- Implement redirect system to avoid code duplication
- Maintain backward compatibility with old URLs
This commit is contained in:
Yannick Le Duc
2025-08-26 22:28:11 +02:00
parent bd4f63b99c
commit caf0478e02
12 changed files with 1040 additions and 110 deletions

View File

@@ -14,6 +14,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/com
import { Badge } from '@/components/ui/badge';
import { Avatar, AvatarFallback } from '@/components/ui/avatar';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import Navigation from '@/components/Navigation';
import AuthGuard from '@/components/AuthGuard';
import { Users, User, Calendar, Mail, Vote, Copy, Check, Upload } from 'lucide-react';
@@ -95,8 +96,11 @@ function CampaignParticipantsPageContent() {
return `${firstName.charAt(0)}${lastName.charAt(0)}`.toUpperCase();
};
const copyVoteLink = (participantId: string) => {
const voteUrl = `${window.location.origin}/campaigns/${campaignId}/vote/${participantId}`;
const copyVoteLink = (participantId: string, shortId?: string) => {
// Utiliser le lien court si disponible, sinon le lien long
const voteUrl = shortId
? `${window.location.origin}/v/${shortId}`
: `${window.location.origin}/campaigns/${campaignId}/vote/${participantId}`;
navigator.clipboard.writeText(voteUrl);
setCopiedParticipantId(participantId);
setTimeout(() => setCopiedParticipantId(null), 2000);
@@ -338,14 +342,18 @@ function CampaignParticipantsPageContent() {
<Input
type="text"
readOnly
value={`${window.location.origin}/campaigns/${campaignId}/vote/${participant.id}`}
value={participant.short_id
? `${window.location.origin}/v/${participant.short_id}`
: 'Génération en cours...'
}
className="flex-1 text-xs bg-white dark:bg-slate-800 border-blue-300 dark:border-blue-600 text-blue-700 dark:text-blue-300 font-mono"
/>
<Button
variant="outline"
size="sm"
onClick={() => copyVoteLink(participant.id)}
onClick={() => copyVoteLink(participant.id, participant.short_id)}
className="text-xs"
disabled={!participant.short_id}
>
{copiedParticipantId === participant.id ? (
<>
@@ -359,24 +367,26 @@ function CampaignParticipantsPageContent() {
</>
)}
</Button>
<Button
variant="outline"
size="sm"
onClick={() => {
setSelectedParticipant(participant);
setShowSendEmailModal(true);
}}
className="text-xs"
>
<Mail className="w-3 h-3 mr-1" />
Envoyer un mail
</Button>
</div>
</div>
</div>
</CardContent>
</Card>
)}
{/* Email Button */}
<Button
variant="outline"
size="sm"
onClick={() => {
setSelectedParticipant(participant);
setShowSendEmailModal(true);
}}
className="text-xs"
>
<Mail className="w-3 h-3 mr-1" />
Envoyer un mail
</Button>
</CardContent>
</Card>
))}