feat: rebrand WinningHunter as AdSeeQ
This commit is contained in:
@@ -25,7 +25,7 @@ export default async function AdminOverviewPage() {
|
||||
return (
|
||||
<div>
|
||||
<div className="mb-6 flex flex-wrap items-end justify-between gap-3">
|
||||
<div><div className="text-sm font-black uppercase tracking-[0.2em] text-violet-600">Kontrol Merkezi</div><h1 className="mt-1 text-3xl font-black">WinningHunter Admin</h1><p className="mt-1 text-slate-500">Kullanıcı, gelir, kredi ve operasyon görünümü.</p></div>
|
||||
<div><div className="text-sm font-black uppercase tracking-[0.2em] text-violet-600">Kontrol Merkezi</div><h1 className="mt-1 text-3xl font-black">AdSeeQ Admin</h1><p className="mt-1 text-slate-500">Kullanıcı, gelir, kredi ve operasyon görünümü.</p></div>
|
||||
<div className="rounded-2xl bg-emerald-50 px-4 py-2 text-sm font-bold text-emerald-700">Sistem aktif</div>
|
||||
</div>
|
||||
<AdminNav />
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Link from "next/link";
|
||||
import { requireUser } from "@/lib/auth/current-user";
|
||||
import { DashboardMobileNav } from "@/components/dashboard-mobile-nav";
|
||||
import { BrandLogo } from "@/components/brand-logo";
|
||||
|
||||
const nav = [
|
||||
["Ads", "/dashboard/ads"],
|
||||
@@ -20,7 +21,7 @@ export default async function DashboardLayout({ children }: { children: React.Re
|
||||
<div className="min-h-screen bg-slate-50">
|
||||
<header className="sticky top-0 z-30 border-b border-slate-200 bg-white/90 backdrop-blur">
|
||||
<div className="mx-auto flex max-w-7xl items-center justify-between px-4 py-4">
|
||||
<Link href="/dashboard/ads" className="text-xl font-black">WinningHunter<span className="text-violet-700">.AI</span></Link>
|
||||
<Link href="/dashboard/ads"><BrandLogo markClassName="h-8 w-8" /></Link>
|
||||
<DashboardMobileNav isAdmin={user.role === "ADMIN"} />
|
||||
<nav className="hidden gap-1 lg:flex">
|
||||
{nav.map(([label, href]) => (
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<rect width="64" height="64" rx="18" fill="#6d28d9"/>
|
||||
<circle cx="29" cy="29" r="16" fill="none" stroke="#fff" stroke-width="7"/>
|
||||
<path d="M41 41 54 54" fill="none" stroke="#fff" stroke-linecap="round" stroke-width="7"/>
|
||||
<path d="m21 29 5 5 11-11" fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 416 B |
+25
-2
@@ -1,9 +1,32 @@
|
||||
import type { Metadata } from "next";
|
||||
import "./globals.css";
|
||||
|
||||
const appUrl = process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3000";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "WinningHunter MVP",
|
||||
description: "Dropshipping reklam ve mağaza istihbaratı MVP"
|
||||
metadataBase: new URL(appUrl),
|
||||
applicationName: "AdSeeQ",
|
||||
title: {
|
||||
default: "AdSeeQ — Reklam ve Trend Zekâsı",
|
||||
template: "%s | AdSeeQ"
|
||||
},
|
||||
description: "Meta reklamlarını, TikTok Shop ürünlerini, yükselen trendleri ve rakip markaları yapay zekâ ile tek panelden keşfedin.",
|
||||
keywords: ["reklam kütüphanesi", "Meta Ads", "TikTok Shop", "trend analizi", "marka takibi", "reklam zekâsı"],
|
||||
alternates: { canonical: "/" },
|
||||
openGraph: {
|
||||
title: "AdSeeQ — Kazanan reklamları ve trendleri keşfedin",
|
||||
description: "Meta Ads, TikTok Shop, Magic AI Trends ve Brand Tracker tek panelde.",
|
||||
url: "/",
|
||||
siteName: "AdSeeQ",
|
||||
locale: "tr_TR",
|
||||
type: "website"
|
||||
},
|
||||
twitter: {
|
||||
card: "summary",
|
||||
title: "AdSeeQ — Reklam ve Trend Zekâsı",
|
||||
description: "Kazanan reklamları, ürünleri ve rakip marka hareketlerini keşfedin."
|
||||
},
|
||||
robots: { index: true, follow: true }
|
||||
};
|
||||
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { BrandLogo } from "@/components/brand-logo";
|
||||
|
||||
function GoogleIcon() {
|
||||
return (
|
||||
@@ -36,6 +37,7 @@ export default function LoginPage() {
|
||||
return (
|
||||
<main className="grid min-h-screen place-items-center bg-slate-50 px-4">
|
||||
<form onSubmit={submit} className="w-full max-w-md rounded-3xl bg-white p-8 shadow-soft">
|
||||
<a href="/" className="mb-7 inline-flex"><BrandLogo /></a>
|
||||
<h1 className="text-3xl font-black">Giriş yap</h1>
|
||||
<p className="mt-2 text-sm text-slate-500">Hesabınızla veya Google üzerinden güvenli giriş yapın.</p>
|
||||
|
||||
|
||||
+4
-3
@@ -1,10 +1,11 @@
|
||||
import { LinkButton } from "@/components/ui/button";
|
||||
import { BrandLogo } from "@/components/brand-logo";
|
||||
|
||||
export default function LandingPage() {
|
||||
return (
|
||||
<main className="min-h-screen overflow-hidden bg-[radial-gradient(circle_at_top_left,#ddd6fe,transparent_35%),#f8fafc]">
|
||||
<nav className="mx-auto flex max-w-7xl items-center justify-between px-6 py-6">
|
||||
<div className="text-xl font-black tracking-tight">WinningHunter<span className="text-violet-700">.AI</span></div>
|
||||
<BrandLogo />
|
||||
<div className="flex gap-3">
|
||||
<LinkButton href="/login" className="bg-white text-slate-900 hover:bg-slate-100">Giriş</LinkButton>
|
||||
<LinkButton href="/pricing">Planlar</LinkButton>
|
||||
@@ -13,13 +14,13 @@ export default function LandingPage() {
|
||||
<section className="mx-auto grid max-w-7xl gap-10 px-6 py-20 lg:grid-cols-[1.05fr_0.95fr] lg:items-center">
|
||||
<div>
|
||||
<div className="mb-5 inline-flex rounded-full border border-violet-200 bg-white/70 px-4 py-2 text-sm font-semibold text-violet-800">
|
||||
Meta Ads + Shopify Store Intelligence MVP
|
||||
Meta Ads + TikTok Shop + AI Trend Intelligence
|
||||
</div>
|
||||
<h1 className="max-w-4xl text-5xl font-black leading-tight tracking-tight text-slate-950 md:text-7xl">
|
||||
Kazanan reklamları ve mağazaları dakikalar içinde keşfet.
|
||||
</h1>
|
||||
<p className="mt-6 max-w-2xl text-lg leading-8 text-slate-600">
|
||||
Dropshipping ve e-ticaret için reklam kütüphanesi, mağaza keşfi, kaydetme, takip ve kota tabanlı üyelik altyapısı tek panelde.
|
||||
Meta reklam kütüphanesi, TikTok Shop ürün keşfi, Magic AI trend analizi ve rakip marka takibi tek panelde.
|
||||
</p>
|
||||
<div className="mt-8 flex flex-wrap gap-3">
|
||||
<LinkButton href="/register" className="px-6 py-3">Ücretsiz başla</LinkButton>
|
||||
|
||||
@@ -2,6 +2,7 @@ import { prisma } from "@/lib/db";
|
||||
import { LinkButton } from "@/components/ui/button";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { CheckoutButton } from "@/components/checkout-button";
|
||||
import { BrandLogo } from "@/components/brand-logo";
|
||||
|
||||
export default async function PricingPage() {
|
||||
const plans = await prisma.plan.findMany({ orderBy: { sortOrder: "asc" } }).catch(() => []);
|
||||
@@ -15,6 +16,7 @@ export default async function PricingPage() {
|
||||
return (
|
||||
<main className="min-h-screen bg-slate-50 px-6 py-12">
|
||||
<div className="mx-auto max-w-6xl">
|
||||
<a href="/" className="mb-10 inline-flex"><BrandLogo /></a>
|
||||
<div className="mb-10 text-center">
|
||||
<h1 className="text-4xl font-black">Fiyatlandırma</h1>
|
||||
<p className="mt-3 text-slate-600">Kota tabanlı freemium model: arama, takip ve API kredileri planlara göre açılır.</p>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { BrandLogo } from "@/components/brand-logo";
|
||||
|
||||
function GoogleIcon() {
|
||||
return (
|
||||
@@ -33,6 +34,7 @@ export default function RegisterPage() {
|
||||
return (
|
||||
<main className="grid min-h-screen place-items-center bg-slate-50 px-4">
|
||||
<form onSubmit={submit} className="w-full max-w-md rounded-3xl bg-white p-8 shadow-soft">
|
||||
<a href="/" className="mb-7 inline-flex"><BrandLogo /></a>
|
||||
<h1 className="text-3xl font-black">Ücretsiz başla</h1>
|
||||
|
||||
<label className="mt-6 block text-sm font-bold">Ad</label>
|
||||
|
||||
@@ -43,7 +43,7 @@ export function ApifyEmptySearch({ query, planLimit }: { query: string; planLimi
|
||||
<div className="rounded-3xl border border-dashed border-violet-200 bg-violet-50/60 p-8 text-center md:col-span-2 xl:col-span-3">
|
||||
<h2 className="text-xl font-black">“{query}” için kayıtlı reklam bulunamadı</h2>
|
||||
<p className="mx-auto mt-2 max-w-2xl text-sm text-slate-600">
|
||||
Bu arama önce WinningHunter veritabanını kontrol eder. Yeni Meta reklamlarını Apify üzerinden getirip aynı aramaya ekleyebilirsiniz.
|
||||
Bu arama önce AdSeeQ veritabanını kontrol eder. Yeni Meta reklamlarını Apify üzerinden getirip aynı aramaya ekleyebilirsiniz.
|
||||
</p>
|
||||
<div className="mx-auto mt-5 flex max-w-sm gap-2">
|
||||
<label className="sr-only" htmlFor="apify-result-count">Getirilecek reklam adedi</label>
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
type BrandLogoProps = {
|
||||
className?: string;
|
||||
markClassName?: string;
|
||||
showWordmark?: boolean;
|
||||
};
|
||||
|
||||
export function BrandLogo({
|
||||
className = "",
|
||||
markClassName = "h-9 w-9",
|
||||
showWordmark = true
|
||||
}: BrandLogoProps) {
|
||||
return (
|
||||
<span className={`inline-flex items-center gap-2.5 ${className}`} aria-label="AdSeeQ">
|
||||
<span className={`inline-flex shrink-0 items-center justify-center rounded-xl bg-violet-700 text-white shadow-sm ${markClassName}`}>
|
||||
<svg viewBox="0 0 32 32" className="h-[72%] w-[72%]" aria-hidden="true">
|
||||
<circle cx="14.5" cy="14.5" r="8" fill="none" stroke="currentColor" strokeWidth="3.4" />
|
||||
<path d="M20.4 20.4 27 27" fill="none" stroke="currentColor" strokeLinecap="round" strokeWidth="3.4" />
|
||||
<path d="M10.5 14.7 13.2 17.4 18.8 11.8" fill="none" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2.5" />
|
||||
</svg>
|
||||
</span>
|
||||
{showWordmark && (
|
||||
<span className="text-xl font-black tracking-[-0.035em] text-slate-950">
|
||||
AdSee<span className="text-violet-700">Q</span>
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
@@ -56,7 +56,7 @@ export function StoreTrackerManager({ tracked, limit }: { tracked: TrackedStoreI
|
||||
<input value={domain} onChange={(event) => setDomain(event.target.value)} required placeholder="ornek-magaza.com" className="min-w-0 flex-1 rounded-2xl border border-slate-200 px-4 py-3" />
|
||||
<button disabled={busy !== null} className="rounded-2xl bg-slate-950 px-5 py-3 font-bold text-white disabled:opacity-50">{busy === "add" ? "Ekleniyor…" : "Mağazayı takip et"}</button>
|
||||
</form>
|
||||
<div className="mb-5 flex flex-wrap items-center justify-between gap-2 text-sm"><span className="text-slate-500">Yalnızca WinningHunter veritabanında bulunan domainler eklenebilir.</span><span className="rounded-full bg-violet-50 px-3 py-1 font-bold text-violet-700">{tracked.length} / {limit === null ? "∞" : limit}</span></div>
|
||||
<div className="mb-5 flex flex-wrap items-center justify-between gap-2 text-sm"><span className="text-slate-500">Yalnızca AdSeeQ veritabanında bulunan domainler eklenebilir.</span><span className="rounded-full bg-violet-50 px-3 py-1 font-bold text-violet-700">{tracked.length} / {limit === null ? "∞" : limit}</span></div>
|
||||
{message && <div className={`mb-4 rounded-xl p-3 text-sm font-semibold ${error ? "bg-rose-50 text-rose-700" : "bg-emerald-50 text-emerald-700"}`}>{message}</div>}
|
||||
<div className="space-y-3">
|
||||
{tracked.map((item) => <div key={item.id} className="flex flex-col gap-3 rounded-2xl bg-slate-50 p-4 sm:flex-row sm:items-center sm:justify-between"><a href={`/dashboard/stores/${item.store.id}`} className="min-w-0"><div className="truncate font-black">{item.store.name}</div><div className="truncate text-sm text-slate-500">{item.store.domain} · {item.store.products.map((product) => product.title).join(", ") || "Bestseller yok"} · €{item.store.estRevenue30dMax?.toLocaleString() || "—"} est.</div></a><button type="button" disabled={busy !== null} onClick={() => removeStore(item.id)} className="shrink-0 rounded-xl border border-rose-200 px-4 py-2 text-sm font-bold text-rose-700 disabled:opacity-50">{busy === item.id ? "Çıkarılıyor…" : "Takibi bırak"}</button></div>)}
|
||||
|
||||
@@ -26,7 +26,7 @@ async function sendAlertEmail(email: string, title: string, brand: string) {
|
||||
const key = process.env.RESEND_API_KEY?.trim();
|
||||
const from = process.env.ALERT_FROM_EMAIL?.trim();
|
||||
if (!key || !from) return false;
|
||||
const response = await fetch("https://api.resend.com/emails", { method: "POST", headers: { authorization: `Bearer ${key}`, "content-type": "application/json" }, body: JSON.stringify({ from, to: [email], subject: `${brand}: yeni reklam`, html: `<p><strong>${brand}</strong> için yeni reklam bulundu.</p><p>${title}</p><p><a href="${process.env.NEXT_PUBLIC_APP_URL || ""}/dashboard/brand-tracker">WinningHunter'da görüntüle</a></p>` }) });
|
||||
const response = await fetch("https://api.resend.com/emails", { method: "POST", headers: { authorization: `Bearer ${key}`, "content-type": "application/json" }, body: JSON.stringify({ from, to: [email], subject: `${brand}: yeni reklam`, html: `<p><strong>${brand}</strong> için yeni reklam bulundu.</p><p>${title}</p><p><a href="${process.env.NEXT_PUBLIC_APP_URL || ""}/dashboard/brand-tracker">AdSeeQ'da görüntüle</a></p>` }) });
|
||||
return response.ok;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user