Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions client/src/components/enhanced-ranking-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
TrendingUp,
TrendingDown,
Minus,
User,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
Expand All @@ -22,6 +23,7 @@ interface EnhancedRankingCardProps {
description: string;
votes: number;
niche?: string | null;
suggestedByUsername?: string;
position?: {
current: number | null;
previous: number | null;
Expand Down Expand Up @@ -332,6 +334,18 @@ export default function EnhancedRankingCard({
})}
</Badge>
)}

{/* Suggested by audience badge */}
{idea.suggestedByUsername && (
<Badge
variant="outline"
className="text-xs bg-blue-50 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300 border-blue-200 dark:border-blue-800"
data-testid={`suggested-badge-${idea.id}`}
>
<User className="w-3 h-3 mr-1" />
{t("ideas.suggestedByAudience")}
</Badge>
)}

{/* Badge de cambio de posición */}
{getTrendIcon()}
Expand Down
8 changes: 5 additions & 3 deletions client/src/components/idea-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -249,13 +249,15 @@ export default function IdeaCard({
</div>
)}

{/* Mostrar badge si la idea fue sugerida por otro usuario */}
{/* Mostrar badge si la idea fue sugerida - username para creador, anónimo para público */}
{idea.suggestedByUsername && (
<div className="text-xs text-gray-500 dark:text-gray-400 mb-3 flex justify-center">
<div className="inline-flex items-center gap-1 bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded-none">
<User className="h-3 w-3" />
{t("ideas.suggestedBy")}:{" "}
<span className="font-medium">{idea.suggestedByUsername}</span>
{isCreator
? `${t("ideas.suggestedBy")}: ${idea.suggestedByUsername}`
: t("ideas.suggestedByAudience")
}
</div>
</div>
)}
Expand Down
11 changes: 7 additions & 4 deletions client/src/components/idea-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,8 @@ export default function IdeaForm({ isOpen, idea, onClose }: IdeaFormProps) {
name="title"
render={({ field }) => (
<FormItem className="space-y-3">
<FormLabel className="text-sm font-semibold text-gray-900 dark:text-white">
<FormLabel className="text-sm font-semibold text-gray-900 dark:text-white flex items-center gap-2">
<span>💡</span>
{t("ideaForm.title", "Title")}
</FormLabel>
<FormControl>
Expand All @@ -274,7 +275,8 @@ export default function IdeaForm({ isOpen, idea, onClose }: IdeaFormProps) {
name="description"
render={({ field }) => (
<FormItem className="space-y-3">
<FormLabel className="text-sm font-semibold text-gray-900 dark:text-white">
<FormLabel className="text-sm font-semibold text-gray-900 dark:text-white flex items-center gap-2">
<span>📝</span>
{t("ideaForm.description", "Description")}
</FormLabel>
<FormControl>
Expand Down Expand Up @@ -302,7 +304,8 @@ export default function IdeaForm({ isOpen, idea, onClose }: IdeaFormProps) {
name="niche"
render={({ field }) => (
<FormItem className="space-y-3">
<FormLabel className="text-sm font-semibold text-gray-900 dark:text-white">
<FormLabel className="text-sm font-semibold text-gray-900 dark:text-white flex items-center gap-2">
<span>🎯</span>
{t("ideaForm.niche", "Niche")}
</FormLabel>
<FormControl>
Expand Down Expand Up @@ -403,7 +406,7 @@ export default function IdeaForm({ isOpen, idea, onClose }: IdeaFormProps) {
disabled={
createMutation.isPending || updateMutation.isPending
}
className="flex-1 sm:flex-none h-12 rounded-md bg-gradient-to-r from-primary to-primary/90 hover:from-primary/90 hover:to-primary text-white font-semibold shadow-lg hover:shadow-xl transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed"
className="flex-1 sm:flex-none h-12 rounded-md border-2 border-primary/30 bg-primary/10 hover:bg-primary/20 text-primary font-semibold transition-all duration-200 disabled:opacity-50 disabled:cursor-not-allowed"
>
{createMutation.isPending || updateMutation.isPending ? (
<span className="flex items-center justify-center">
Expand Down
15 changes: 15 additions & 0 deletions client/src/components/idea-list-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,21 @@ export default function IdeaListView({
{t("ideas.analyzed", "Analizado")}
</Badge>
)}

{/* Suggested by badge - show username for creator, anonymous for public */}
{idea.suggestedByUsername && (
<Badge
variant="outline"
className="bg-gray-50 dark:bg-gray-800 text-gray-600 dark:text-gray-400 border-gray-200 dark:border-gray-700 text-xs px-2.5 py-1 font-medium rounded-full"
data-testid={`suggested-by-${idea.id}`}
>
<User className="w-3 h-3 mr-1" />
{isCreator
? `${t("ideas.suggestedBy")}: ${idea.suggestedByUsername}`
: t("ideas.suggestedByAudience")
}
</Badge>
)}
</div>

{/* Title */}
Expand Down
13 changes: 12 additions & 1 deletion client/src/components/ideas-list.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { motion } from "framer-motion";
import { TrendingUp, Loader2 } from "lucide-react";
import { TrendingUp, Loader2, User } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { IdeaResponse } from "@shared/schema";
import { useTranslation } from "react-i18next";
import { cn } from "@/lib/utils";
Expand Down Expand Up @@ -88,6 +89,16 @@ export function IdeasList({
<p className="text-xs text-gray-600 dark:text-gray-400 line-clamp-2 leading-relaxed">
{idea.description}
</p>
{idea.suggestedByUsername && (
<Badge
variant="outline"
className="mt-2 text-xs bg-blue-50 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300 border-blue-200 dark:border-blue-800"
data-testid={`suggested-badge-list-${idea.id}`}
>
<User className="w-3 h-3 mr-1" />
{t("ideas.suggestedByAudience")}
</Badge>
)}
</div>

<div className="flex-shrink-0 flex items-center gap-3">
Expand Down
20 changes: 11 additions & 9 deletions client/src/components/ideas-tab-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -563,25 +563,25 @@ export function IdeasTabView({ mode = "published", onOpenTemplate }: IdeasTabVie
key={idea.id}
className="group bg-white/80 dark:bg-gray-900/80 backdrop-blur-sm border border-gray-200/50 dark:border-gray-700/50 rounded-2xl p-4 hover:bg-white/90 dark:hover:bg-gray-900/90 hover:shadow-lg transition-all duration-300 hover:border-gray-300/60 dark:hover:border-gray-600/60"
>
<div className="flex items-start gap-4">
{/* Position */}
<div className="flex-shrink-0 flex flex-col items-center">
<div className="text-xl font-bold text-amber-600 dark:text-amber-400 min-w-[2rem] text-center">
<div className="flex flex-col sm:flex-row sm:items-start gap-3 sm:gap-4">
{/* Position - horizontal on mobile, vertical on desktop */}
<div className="flex-shrink-0 flex flex-row sm:flex-col items-center gap-2 sm:gap-0">
<div className="text-lg sm:text-xl font-bold text-amber-600 dark:text-amber-400 min-w-[2rem] text-center">
#{index + 1}
</div>
<Badge
variant="outline"
className="bg-amber-100 text-amber-700 border-amber-200 dark:bg-amber-900/30 dark:text-amber-300 dark:border-amber-800 text-xs mt-1"
className="bg-amber-100 text-amber-700 border-amber-200 dark:bg-amber-900/30 dark:text-amber-300 dark:border-amber-800 text-xs sm:mt-1"
>
<Clock className="h-3 w-3 mr-1" /> {t("ideas.pending", "Pendiente")}
</Badge>
</div>

{/* Content */}
<div className="flex-1 min-w-0">
<div className="flex items-start justify-between gap-3">
<div className="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-3">
<div className="flex-1 min-w-0">
<h3 className="text-lg font-semibold text-gray-900 dark:text-white mb-2 line-clamp-2">
<h3 className="text-base sm:text-lg font-semibold text-gray-900 dark:text-white mb-2 line-clamp-2">
{idea.title}
</h3>
{idea.description && (
Expand Down Expand Up @@ -615,7 +615,8 @@ export function IdeasTabView({ mode = "published", onOpenTemplate }: IdeasTabVie
) : (
<>
<XCircle className="h-4 w-4 mr-1" />
{t("ideas.reject", "Rechazar")}
<span className="hidden sm:inline">{t("ideas.reject", "Rechazar")}</span>
<span className="sm:hidden">{t("ideas.reject", "Rechazar")}</span>
</>
)}
</Button>
Expand All @@ -631,7 +632,8 @@ export function IdeasTabView({ mode = "published", onOpenTemplate }: IdeasTabVie
) : (
<>
<CheckCircle className="h-4 w-4 mr-1" />
{t("ideas.approve", "Aprobar")}
<span className="hidden sm:inline">{t("ideas.approve", "Aprobar")}</span>
<span className="sm:hidden">{t("ideas.approve", "Aprobar")}</span>
</>
)}
</Button>
Expand Down
16 changes: 11 additions & 5 deletions client/src/components/top3-cards.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { motion } from "framer-motion";
import { Trophy, TrendingUp } from "lucide-react";
import { Trophy, TrendingUp, User } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { IdeaResponse } from "@shared/schema";
import { useTranslation } from "react-i18next";
import { cn } from "@/lib/utils";
Expand Down Expand Up @@ -121,10 +122,15 @@ export function Top3Cards({
</div>

<div className="flex items-center justify-between mt-auto">
{idea.suggestedBy && (
<span className="text-xs text-gray-500 dark:text-gray-400">
{t("ideas.by", "Por")} {idea.suggestedBy}
</span>
{idea.suggestedByUsername && (
<Badge
variant="outline"
className="text-xs bg-blue-50 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300 border-blue-200 dark:border-blue-800"
data-testid={`suggested-badge-top3-${idea.id}`}
>
<User className="w-3 h-3 mr-1" />
{t("ideas.suggestedByAudience")}
</Badge>
)}
<Button
onClick={() => handleVoteClick(idea.id)}
Expand Down
17 changes: 16 additions & 1 deletion client/src/components/top3-podium.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { motion } from "framer-motion";
import { Trophy, Medal, Award, Sparkles } from "lucide-react";
import { Trophy, Medal, Award, Sparkles, User } from "lucide-react";
import { Card, CardContent } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
Expand Down Expand Up @@ -373,6 +373,21 @@ function PodiumCard({
)}>
{idea.description}
</p>

{/* Suggested by audience badge */}
{idea.suggestedByUsername && (
<Badge
variant="outline"
className={cn(
"mt-2 text-xs bg-blue-50 text-blue-700 dark:bg-blue-900/30 dark:text-blue-300 border-blue-200 dark:border-blue-800 w-fit",
isMobile ? "text-[10px] px-1.5 py-0.5" : ""
)}
data-testid={`suggested-badge-podium-${idea.id}`}
>
<User className={cn("mr-1", isMobile ? "w-2.5 h-2.5" : "w-3 h-3")} />
{t("ideas.suggestedByAudience")}
</Badge>
)}
</div>

{/* Vote Section */}
Expand Down
34 changes: 19 additions & 15 deletions client/src/components/video-template-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ interface Section {
labelKey: string;
placeholderKey: string;
icon: typeof Eye;
emoji?: string;
}

export default function VideoTemplateModal({
Expand All @@ -70,15 +71,15 @@ export default function VideoTemplateModal({
const { user } = useAuth();
const isPremium = user ? hasActivePremiumAccess(user) : false;

// Define sections with translation keys
// Define sections with translation keys and emojis
const sections: Section[] = [
{ key: "hook", labelKey: "videoScript.sections.hook", placeholderKey: "videoScript.sections.hookPlaceholder", icon: Eye },
{ key: "teaser", labelKey: "videoScript.sections.teaser", placeholderKey: "videoScript.sections.teaserPlaceholder", icon: Eye },
{ key: "valorAudiencia", labelKey: "videoScript.sections.valueForAudience", placeholderKey: "videoScript.sections.valueForAudiencePlaceholder", icon: Eye },
{ key: "pointsToCover", labelKey: "videoScript.sections.pointsToCover", placeholderKey: "videoScript.sections.pointsToCoverPlaceholder", icon: Eye },
{ key: "visualsNeeded", labelKey: "videoScript.sections.visualsNeeded", placeholderKey: "videoScript.sections.visualsNeededPlaceholder", icon: Eye },
{ key: "bonus", labelKey: "videoScript.sections.bonus", placeholderKey: "videoScript.sections.bonusPlaceholder", icon: Eye },
{ key: "outro", labelKey: "videoScript.sections.outro", placeholderKey: "videoScript.sections.outroPlaceholder", icon: Eye },
{ key: "hook", labelKey: "videoScript.sections.hook", placeholderKey: "videoScript.sections.hookPlaceholder", icon: Eye, emoji: "🎣" },
{ key: "teaser", labelKey: "videoScript.sections.teaser", placeholderKey: "videoScript.sections.teaserPlaceholder", icon: Eye, emoji: "✨" },
{ key: "valorAudiencia", labelKey: "videoScript.sections.valueForAudience", placeholderKey: "videoScript.sections.valueForAudiencePlaceholder", icon: Eye, emoji: "💎" },
{ key: "pointsToCover", labelKey: "videoScript.sections.pointsToCover", placeholderKey: "videoScript.sections.pointsToCoverPlaceholder", icon: Eye, emoji: "📋" },
{ key: "visualsNeeded", labelKey: "videoScript.sections.visualsNeeded", placeholderKey: "videoScript.sections.visualsNeededPlaceholder", icon: Eye, emoji: "🎬" },
{ key: "bonus", labelKey: "videoScript.sections.bonus", placeholderKey: "videoScript.sections.bonusPlaceholder", icon: Eye, emoji: "🎁" },
{ key: "outro", labelKey: "videoScript.sections.outro", placeholderKey: "videoScript.sections.outroPlaceholder", icon: Eye, emoji: "👋" },
];

// Text fields
Expand Down Expand Up @@ -288,17 +289,17 @@ ${outro.length > 0 ? `## OUTRO / CTA\n${formatItems(outro)}\n` : ''}
<CollapsibleTrigger asChild>
<Button
variant="outline"
className="w-full flex items-center justify-between p-4 hover:bg-gray-50 dark:hover:bg-gray-800"
className="w-full flex items-center justify-between p-4 border-2 border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 text-gray-900 dark:text-white"
data-testid={`toggle-${section.key}`}
>
<span className="font-semibold flex items-center gap-2">
<Icon className="w-4 h-4" />
{section.emoji && <span>{section.emoji}</span>}
{t(section.labelKey)} ({items.length})
</span>
{isOpen ? (
<ChevronUp className="w-4 h-4" />
<ChevronUp className="w-4 h-4 text-gray-500" />
) : (
<ChevronDown className="w-4 h-4" />
<ChevronDown className="w-4 h-4 text-gray-500" />
)}
</Button>
</CollapsibleTrigger>
Expand Down Expand Up @@ -345,13 +346,14 @@ ${outro.length > 0 ? `## OUTRO / CTA\n${formatItems(outro)}\n` : ''}
onChange={(e) => setNewInputs({ ...newInputs, [section.key]: e.target.value })}
placeholder={t(section.placeholderKey)}
onKeyPress={(e) => e.key === "Enter" && handleAddItem(section.key)}
className="flex-1"
className="flex-1 border-2 border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 focus:border-primary/50 text-gray-900 dark:text-white"
data-testid={`input-new-${section.key}`}
/>
<Button
onClick={() => handleAddItem(section.key)}
size="sm"
variant="outline"
className="border-2 border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300"
data-testid={`button-add-${section.key}`}
>
<Plus className="w-4 h-4 mr-1" />
Expand All @@ -365,7 +367,7 @@ ${outro.length > 0 ? `## OUTRO / CTA\n${formatItems(outro)}\n` : ''}

return (
<Dialog open={isOpen} onOpenChange={onClose}>
<DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto">
<DialogContent className="max-w-4xl max-h-[90vh] overflow-y-auto bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700">
<DialogHeader>
<DialogTitle className="flex items-center gap-2 text-2xl">
<FileText className="w-6 h-6 text-primary" />
Expand Down Expand Up @@ -450,7 +452,7 @@ ${outro.length > 0 ? `## OUTRO / CTA\n${formatItems(outro)}\n` : ''}
<Button
onClick={handleSave}
disabled={saveMutation.isPending}
className="flex-1"
className="flex-1 border-2 border-primary/30 bg-primary/10 hover:bg-primary/20 text-primary font-semibold transition-all duration-200 disabled:opacity-50"
data-testid="button-save-template"
>
{saveMutation.isPending ? (
Expand All @@ -468,6 +470,7 @@ ${outro.length > 0 ? `## OUTRO / CTA\n${formatItems(outro)}\n` : ''}
<Button
onClick={handleExportMarkdown}
variant="outline"
className="border-2 border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300"
data-testid="button-export-template"
>
<Download className="w-4 h-4 mr-2" />
Expand All @@ -476,6 +479,7 @@ ${outro.length > 0 ? `## OUTRO / CTA\n${formatItems(outro)}\n` : ''}
<Button
onClick={onClose}
variant="outline"
className="border-2 border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800 hover:bg-gray-50 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-300"
data-testid="button-close-template"
>
{t("videoScript.close")}
Expand Down
1 change: 1 addition & 0 deletions client/src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@
"noSuggestedIdeas": "No suggestions yet",
"suggestedIdeasWillAppear": "Suggested ideas from your audience will appear here",
"suggestedBy": "Suggested by",
"suggestedByAudience": "Suggested by audience",
"pending": "Pending",
"approve": "Approve",
"reject": "Reject",
Expand Down
1 change: 1 addition & 0 deletions client/src/locales/es/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,7 @@
"noSuggestedIdeas": "Aún no hay sugerencias",
"suggestedIdeasWillAppear": "Las ideas sugeridas por tu audiencia aparecerán aquí",
"suggestedBy": "Sugerida por",
"suggestedByAudience": "Sugerida por la audiencia",
"pending": "Pendiente",
"approve": "Aprobar",
"reject": "Rechazar",
Expand Down
Loading