feat: add terms and privacy pages, replace favorite with share on job cards

This commit is contained in:
Tiago Yamamoto 2026-02-23 20:56:17 -06:00
parent cf761a70e4
commit 1b897eeb8e
5 changed files with 78 additions and 64 deletions

View file

@ -26,6 +26,18 @@ export function Footer() {
{t("footerMain.info.contact")}
</Link>
</li>
<li className="flex items-center gap-2">
<span className="w-1.5 h-1.5 bg-gray-400 rounded-full inline-block"></span>
<Link href="/terms" className="text-sm text-gray-600 hover:text-primary transition-colors">
{t("footerMain.info.terms") || "Termos de Uso"}
</Link>
</li>
<li className="flex items-center gap-2">
<span className="w-1.5 h-1.5 bg-gray-400 rounded-full inline-block"></span>
<Link href="/privacy" className="text-sm text-gray-600 hover:text-primary transition-colors">
{t("footerMain.info.privacy") || "Política de Privacidade"}
</Link>
</li>
</ul>
</div>

View file

@ -9,14 +9,25 @@ import {
} from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import {
MapPin,
Briefcase,
Clock,
Building2,
Heart,
Share2,
Zap,
Link2,
MessageCircle,
Linkedin,
Twitter,
Facebook
} from "lucide-react";
import Link from "next/link";
import { motion } from "framer-motion";
@ -35,53 +46,27 @@ interface JobCardProps {
export function JobCard({ job, isApplied, applicationStatus }: JobCardProps) {
const { t } = useTranslation();
const { user } = useAuth();
const [isFavorited, setIsFavorited] = useState(false);
const [isLoading, setIsLoading] = useState(true);
const notify = useNotify();
const handleShare = (platform: string) => {
const url = typeof window !== "undefined" ? `${window.location.origin}/jobs/${job.id}` : `https://local.gohorsejobs.com/jobs/${job.id}`;
const text = `Confira esta vaga: ${job.title} na ${job.company}`;
useEffect(() => {
const checkFavorite = async () => {
if (!user) {
setIsLoading(false);
return;
}
try {
const res = await jobsApi.checkFavorite(job.id);
setIsFavorited(res.isFavorite);
} catch {
// User not logged in or error - ignore
} finally {
setIsLoading(false);
}
};
checkFavorite();
}, [job.id, user]);
const handleFavorite = async () => {
if (isLoading) return;
if (!user) {
notify.error("Erro", "Faça login para salvar vagas.");
return;
}
try {
if (isFavorited) {
await jobsApi.removeFavorite(job.id);
setIsFavorited(false);
} else {
await jobsApi.addFavorite(job.id);
setIsFavorited(true);
notify.info(
t('jobs.favorites.added.title'),
t('jobs.favorites.added.desc', { title: job.title }),
{
actionUrl: "/dashboard/favorites",
actionLabel: t('jobs.favorites.action'),
}
);
}
} catch {
notify.error("Erro", "Faça login para salvar vagas.");
switch (platform) {
case 'whatsapp':
window.open(`https://wa.me/?text=${encodeURIComponent(text + " " + url)}`, '_blank');
break;
case 'linkedin':
window.open(`https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(url)}`, '_blank');
break;
case 'twitter':
window.open(`https://twitter.com/intent/tweet?url=${encodeURIComponent(url)}&text=${encodeURIComponent(text)}`, '_blank');
break;
case 'facebook':
window.open(`https://www.facebook.com/sharer/sharer.php?u=${encodeURIComponent(url)}`, '_blank');
break;
case 'copy':
navigator.clipboard.writeText(url);
notify.success("Link copiado!", "Link da vaga copiado para a área de transferência.");
break;
}
};
@ -169,19 +154,30 @@ export function JobCard({ job, isApplied, applicationStatus }: JobCardProps) {
</div>
</div>
<Button
variant="ghost"
size="icon"
onClick={handleFavorite}
className="shrink-0"
>
<Heart
className={`h-4 w-4 transition-colors ${isFavorited
? "fill-red-500 text-red-500"
: "text-muted-foreground hover:text-red-500"
}`}
/>
</Button>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="shrink-0 text-muted-foreground hover:text-primary transition-colors">
<Share2 className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-48">
<DropdownMenuItem onClick={() => handleShare('whatsapp')} className="gap-2 cursor-pointer">
<MessageCircle className="h-4 w-4 text-green-600" /> WhatsApp
</DropdownMenuItem>
<DropdownMenuItem onClick={() => handleShare('linkedin')} className="gap-2 cursor-pointer">
<Linkedin className="h-4 w-4 text-blue-600" /> LinkedIn
</DropdownMenuItem>
<DropdownMenuItem onClick={() => handleShare('twitter')} className="gap-2 cursor-pointer">
<Twitter className="h-4 w-4 text-sky-500" /> Twitter/X
</DropdownMenuItem>
<DropdownMenuItem onClick={() => handleShare('facebook')} className="gap-2 cursor-pointer">
<Facebook className="h-4 w-4 text-blue-700" /> Facebook
</DropdownMenuItem>
<DropdownMenuItem onClick={() => handleShare('copy')} className="gap-2 cursor-pointer border-t mt-1 pt-1">
<Link2 className="h-4 w-4 text-gray-500" /> Copiar Link
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</CardHeader>

View file

@ -1379,7 +1379,9 @@
"info": {
"title": "Information",
"about": "About Us",
"contact": "Contact"
"contact": "Contact",
"terms": "Terms of Use",
"privacy": "Privacy Policy"
},
"candidates": {
"title": "For Candidates",

View file

@ -1380,7 +1380,9 @@
"info": {
"title": "Información",
"about": "Sobre nosotros",
"contact": "Contacto"
"contact": "Contacto",
"terms": "Términos de Uso",
"privacy": "Política de Privacidad"
},
"candidates": {
"title": "Para Candidatos",

View file

@ -1386,9 +1386,11 @@
},
"footerMain": {
"info": {
"title": "Informações",
"title": "Informação",
"about": "Sobre nós",
"contact": "Contato"
"contact": "Contato",
"terms": "Termos de Uso",
"privacy": "Política de Privacidade"
},
"candidates": {
"title": "Para Candidatos",