Add agency plans: Starter(1000/55) Growth(3000/99) Scale(5000/499) Enterprise(10000/222) - no unlimited for agencies
This commit is contained in:
+140
-17
@@ -18,12 +18,20 @@ router = APIRouter(prefix="/autojobs/api")
|
|||||||
|
|
||||||
# --- Plans & Pricing ---
|
# --- Plans & Pricing ---
|
||||||
PLANS = {
|
PLANS = {
|
||||||
"free": {"name": "Free", "applications": 5, "ai_customize": 5, "price": 0},
|
"free": {"name": "Free", "applications": 5, "ai_customize": 5, "price": 0, "type": "jobseeker"},
|
||||||
"starter": {"name": "Starter", "applications": 50, "ai_customize": 50, "price": 9},
|
"starter": {"name": "Starter", "applications": 50, "ai_customize": 50, "price": 9, "type": "jobseeker"},
|
||||||
"pro": {"name": "Pro", "applications": 100, "ai_customize": 100, "price": 39},
|
"pro": {"name": "Pro", "applications": 100, "ai_customize": 100, "price": 39, "type": "jobseeker"},
|
||||||
"ultra": {"name": "Ultra", "applications": 200, "ai_customize": 200, "price": 69},
|
"ultra": {"name": "Ultra", "applications": 200, "ai_customize": 200, "price": 69, "type": "jobseeker"},
|
||||||
"business": {"name": "Business", "applications": 500, "ai_customize": 500, "price": 119},
|
"business": {"name": "Business", "applications": 500, "ai_customize": 500, "price": 119, "type": "jobseeker"},
|
||||||
"unlimited": {"name": "Unlimited", "applications": 99999, "ai_customize": 99999, "price": 319},
|
"unlimited": {"name": "Unlimited", "applications": 99999, "ai_customize": 99999, "price": 319, "type": "jobseeker"},
|
||||||
|
}
|
||||||
|
|
||||||
|
# Agency Plans (recruiting agencies - manage multiple clients)
|
||||||
|
AGENCY_PLANS = {
|
||||||
|
"agency_starter": {"name": "Agency Starter", "submissions": 1000, "clients": 10, "price": 555, "type": "agency"},
|
||||||
|
"agency_growth": {"name": "Agency Growth", "submissions": 3000, "clients": 50, "price": 999, "type": "agency"},
|
||||||
|
"agency_scale": {"name": "Agency Scale", "submissions": 5000, "clients": 150, "price": 1499, "type": "agency"},
|
||||||
|
"agency_enterprise": {"name": "Agency Enterprise", "submissions": 10000, "clients": 500, "price": 2222, "type": "agency"},
|
||||||
}
|
}
|
||||||
|
|
||||||
# --- Database ---
|
# --- Database ---
|
||||||
@@ -76,6 +84,20 @@ def init_db():
|
|||||||
)
|
)
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
# Agency client profiles
|
||||||
|
c.execute("""
|
||||||
|
CREATE TABLE IF NOT EXISTS client_profiles (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
agency_id TEXT NOT NULL,
|
||||||
|
client_name TEXT,
|
||||||
|
client_email TEXT,
|
||||||
|
profile_data TEXT DEFAULT '{}',
|
||||||
|
submission_count INTEGER DEFAULT 0,
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
FOREIGN KEY (agency_id) REFERENCES users(id)
|
||||||
|
)
|
||||||
|
""")
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
@@ -111,8 +133,20 @@ def get_user_row(user_id: str):
|
|||||||
def check_plan_limit(user: dict, action: str, count: int = 1) -> dict:
|
def check_plan_limit(user: dict, action: str, count: int = 1) -> dict:
|
||||||
"""Check if user has reached their plan limit. Returns {"allowed": bool, "remaining": int}"""
|
"""Check if user has reached their plan limit. Returns {"allowed": bool, "remaining": int}"""
|
||||||
plan_name = user.get("plan", "free")
|
plan_name = user.get("plan", "free")
|
||||||
|
|
||||||
|
# Check if agency plan
|
||||||
|
if plan_name in AGENCY_PLANS:
|
||||||
|
plan = AGENCY_PLANS[plan_name]
|
||||||
|
if action == "submission":
|
||||||
|
used = user.get("monthly_count", 0)
|
||||||
|
limit = plan["submissions"]
|
||||||
|
else:
|
||||||
|
return {"allowed": True, "remaining": 99999}
|
||||||
|
remaining = max(0, limit - used)
|
||||||
|
return {"allowed": remaining >= count, "remaining": remaining, "limit": limit, "used": used, "type": "agency"}
|
||||||
|
|
||||||
|
# Jobseeker plan
|
||||||
plan = PLANS.get(plan_name, PLANS["free"])
|
plan = PLANS.get(plan_name, PLANS["free"])
|
||||||
|
|
||||||
if action == "application":
|
if action == "application":
|
||||||
used = user.get("monthly_count", 0)
|
used = user.get("monthly_count", 0)
|
||||||
limit = plan["applications"]
|
limit = plan["applications"]
|
||||||
@@ -123,12 +157,12 @@ def check_plan_limit(user: dict, action: str, count: int = 1) -> dict:
|
|||||||
return {"allowed": True, "remaining": 99999}
|
return {"allowed": True, "remaining": 99999}
|
||||||
|
|
||||||
remaining = max(0, limit - used)
|
remaining = max(0, limit - used)
|
||||||
return {"allowed": remaining >= count, "remaining": remaining, "limit": limit, "used": used}
|
return {"allowed": remaining >= count, "remaining": remaining, "limit": limit, "used": used, "type": "jobseeker"}
|
||||||
|
|
||||||
def increment_usage(user_id: str, action: str):
|
def increment_usage(user_id: str, action: str):
|
||||||
conn = sqlite3.connect(DB_PATH)
|
conn = sqlite3.connect(DB_PATH)
|
||||||
c = conn.cursor()
|
c = conn.cursor()
|
||||||
if action == "application":
|
if action == "submission":
|
||||||
c.execute("UPDATE users SET monthly_count = monthly_count + 1 WHERE id = ?", (user_id,))
|
c.execute("UPDATE users SET monthly_count = monthly_count + 1 WHERE id = ?", (user_id,))
|
||||||
elif action == "ai_customize":
|
elif action == "ai_customize":
|
||||||
c.execute("UPDATE users SET ai_customize_count = ai_customize_count + 1 WHERE id = ?", (user_id,))
|
c.execute("UPDATE users SET ai_customize_count = ai_customize_count + 1 WHERE id = ?", (user_id,))
|
||||||
@@ -315,8 +349,11 @@ def get_profile(user=Depends(get_current_user)):
|
|||||||
|
|
||||||
@router.get("/plans")
|
@router.get("/plans")
|
||||||
def list_plans():
|
def list_plans():
|
||||||
"""List all available plans"""
|
"""List all available plans (jobseeker + agency)"""
|
||||||
return {"plans": PLANS}
|
return {
|
||||||
|
"jobseeker_plans": PLANS,
|
||||||
|
"agency_plans": AGENCY_PLANS
|
||||||
|
}
|
||||||
|
|
||||||
# --- Job Search ---
|
# --- Job Search ---
|
||||||
@router.post("/jobs/search")
|
@router.post("/jobs/search")
|
||||||
@@ -504,17 +541,20 @@ def submit_application(app_data: ApplicationSubmit, user=Depends(get_current_use
|
|||||||
if not user_row:
|
if not user_row:
|
||||||
raise HTTPException(status_code=404, detail="User not found")
|
raise HTTPException(status_code=404, detail="User not found")
|
||||||
|
|
||||||
# Check plan limit
|
# Check plan limit (use "submission" for agency, "application" for jobseeker)
|
||||||
check = check_plan_limit(user_row, "application")
|
plan_name = user_row.get("plan", "free")
|
||||||
|
action = "submission" if plan_name in AGENCY_PLANS else "application"
|
||||||
|
check = check_plan_limit(user_row, action)
|
||||||
if not check["allowed"]:
|
if not check["allowed"]:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=402,
|
status_code=402,
|
||||||
detail={
|
detail={
|
||||||
"error": "Application limit reached",
|
"error": "Limit reached",
|
||||||
"plan": user_row["plan"],
|
"plan": plan_name,
|
||||||
"limit": check["limit"],
|
"limit": check["limit"],
|
||||||
"used": check["used"],
|
"used": check["used"],
|
||||||
"message": f"You've applied to {check['used']} jobs this billing cycle. Upgrade your plan for more applications."
|
"type": check.get("type", "jobseeker"),
|
||||||
|
"message": f"You've used {check['used']} of your {check['limit']} submissions this billing cycle. Upgrade your plan for more."
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -541,7 +581,8 @@ def submit_application(app_data: ApplicationSubmit, user=Depends(get_current_use
|
|||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
# Increment usage
|
# Increment usage
|
||||||
increment_usage(user["id"], "application")
|
action = "submission" if plan_name in AGENCY_PLANS else "application"
|
||||||
|
increment_usage(user["id"], action)
|
||||||
|
|
||||||
return {"id": app_id, "status": "submitted"}
|
return {"id": app_id, "status": "submitted"}
|
||||||
|
|
||||||
@@ -648,6 +689,88 @@ def admin_applications(limit: int = 100):
|
|||||||
conn.close()
|
conn.close()
|
||||||
return {"applications": [dict(r) for r in rows]}
|
return {"applications": [dict(r) for r in rows]}
|
||||||
|
|
||||||
|
# --- Agency Routes ---
|
||||||
|
@router.post("/agency/clients")
|
||||||
|
def create_client(client_data: dict, user=Depends(get_current_user)):
|
||||||
|
"""Create a client profile under the agency account"""
|
||||||
|
plan_name = user.get("id") # We need to check plan from user dict
|
||||||
|
user_row = get_user_row(user["id"])
|
||||||
|
if not user_row or user_row["plan"] not in AGENCY_PLANS:
|
||||||
|
raise HTTPException(status_code=403, detail="Agency plan required")
|
||||||
|
|
||||||
|
plan = AGENCY_PLANS[user_row["plan"]]
|
||||||
|
# Check client limit
|
||||||
|
conn = sqlite3.connect(DB_PATH)
|
||||||
|
conn.row_factory = sqlite3.Row
|
||||||
|
c = conn.cursor()
|
||||||
|
c.execute("SELECT COUNT(*) as count FROM client_profiles WHERE agency_id = ?", (user["id"],))
|
||||||
|
current_clients = c.fetchone()["count"]
|
||||||
|
|
||||||
|
if current_clients >= plan["clients"]:
|
||||||
|
conn.close()
|
||||||
|
raise HTTPException(status_code=402, detail=f"Client limit reached. Your plan allows {plan['clients']} clients.")
|
||||||
|
|
||||||
|
client_id = str(uuid.uuid4())
|
||||||
|
c.execute("""
|
||||||
|
INSERT INTO client_profiles (id, agency_id, client_name, client_email, profile_data)
|
||||||
|
VALUES (?, ?, ?, ?, ?)
|
||||||
|
""", (
|
||||||
|
client_id,
|
||||||
|
user["id"],
|
||||||
|
client_data.get("name", ""),
|
||||||
|
client_data.get("email", ""),
|
||||||
|
json.dumps(client_data.get("profile", {}))
|
||||||
|
))
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
return {"client_id": client_id, "name": client_data.get("name", "")}
|
||||||
|
|
||||||
|
@router.get("/agency/clients")
|
||||||
|
def list_clients(user=Depends(get_current_user)):
|
||||||
|
"""List all clients under agency account"""
|
||||||
|
user_row = get_user_row(user["id"])
|
||||||
|
if not user_row or user_row["plan"] not in AGENCY_PLANS:
|
||||||
|
raise HTTPException(status_code=403, detail="Agency plan required")
|
||||||
|
|
||||||
|
conn = sqlite3.connect(DB_PATH)
|
||||||
|
conn.row_factory = sqlite3.Row
|
||||||
|
c = conn.cursor()
|
||||||
|
c.execute("SELECT * FROM client_profiles WHERE agency_id = ? ORDER BY created_at DESC", (user["id"],))
|
||||||
|
rows = c.fetchall()
|
||||||
|
conn.close()
|
||||||
|
return {"clients": [dict(r) for r in rows]}
|
||||||
|
|
||||||
|
@router.get("/agency/usage")
|
||||||
|
def agency_usage(user=Depends(get_current_user)):
|
||||||
|
"""Get agency submission usage"""
|
||||||
|
user_row = get_user_row(user["id"])
|
||||||
|
if not user_row or user_row["plan"] not in AGENCY_PLANS:
|
||||||
|
raise HTTPException(status_code=403, detail="Agency plan required")
|
||||||
|
|
||||||
|
plan = AGENCY_PLANS[user_row["plan"]]
|
||||||
|
return {
|
||||||
|
"plan": user_row["plan"],
|
||||||
|
"submissions_limit": plan["submissions"],
|
||||||
|
"submissions_used": user_row["monthly_count"],
|
||||||
|
"submissions_remaining": max(0, plan["submissions"] - user_row["monthly_count"]),
|
||||||
|
"clients_limit": plan["clients"],
|
||||||
|
"clients_used": len([]), # Will be populated from DB
|
||||||
|
}
|
||||||
|
|
||||||
|
@router.delete("/agency/clients/{client_id}")
|
||||||
|
def delete_client(client_id: str, user=Depends(get_current_user)):
|
||||||
|
"""Delete a client profile"""
|
||||||
|
user_row = get_user_row(user["id"])
|
||||||
|
if not user_row or user_row["plan"] not in AGENCY_PLANS:
|
||||||
|
raise HTTPException(status_code=403, detail="Agency plan required")
|
||||||
|
|
||||||
|
conn = sqlite3.connect(DB_PATH)
|
||||||
|
c = conn.cursor()
|
||||||
|
c.execute("DELETE FROM client_profiles WHERE id = ? AND agency_id = ?", (client_id, user["id"]))
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
return {"deleted": True}
|
||||||
|
|
||||||
@router.post("/admin/reset-usage")
|
@router.post("/admin/reset-usage")
|
||||||
def admin_reset_usage(user_id: str = None):
|
def admin_reset_usage(user_id: str = None):
|
||||||
"""Admin: Reset usage counts (monthly billing cycle reset)"""
|
"""Admin: Reset usage counts (monthly billing cycle reset)"""
|
||||||
|
|||||||
+130
-67
@@ -1,56 +1,103 @@
|
|||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
|
|
||||||
const plans = [
|
const jobseekerPlans = [
|
||||||
{
|
{
|
||||||
name: "Free",
|
name: "Free",
|
||||||
price: "$0",
|
price: "$0",
|
||||||
period: "forever",
|
period: "forever",
|
||||||
apps: "5",
|
apps: "5",
|
||||||
ai: "5",
|
badge: "",
|
||||||
badge: "Start Here",
|
|
||||||
highlight: false,
|
highlight: false,
|
||||||
features: ["5 AI job applications/month", "5 AI resume customizations/month", "Application tracker", "Add your own API keys", "Multi-source search"],
|
features: ["5 AI job applications/month", "5 AI resume customizations/month", "Application tracker", "Add your own API keys"],
|
||||||
cta: "Get Started Free",
|
cta: "Get Started",
|
||||||
ctaStyle: "bg-white/10 hover:bg-white/20"
|
ctaStyle: "bg-white/10 hover:bg-white/20"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Starter",
|
name: "Starter",
|
||||||
price: "$9",
|
price: "$9",
|
||||||
period: "/month",
|
period: "/mo",
|
||||||
apps: "50",
|
apps: "50",
|
||||||
ai: "50",
|
|
||||||
badge: "",
|
badge: "",
|
||||||
highlight: false,
|
highlight: false,
|
||||||
features: ["50 AI job applications/month", "50 AI resume customizations/month", "Application tracker", "Add your own API keys", "Email notifications"],
|
features: ["50 AI job applications/month", "50 AI resume customizations/month", "Application tracker", "Add your own API keys"],
|
||||||
cta: "Start Applying",
|
cta: "Start Applying",
|
||||||
ctaStyle: "bg-blue-500 hover:bg-blue-600"
|
ctaStyle: "bg-blue-500 hover:bg-blue-600"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Pro",
|
name: "Pro",
|
||||||
price: "$39",
|
price: "$39",
|
||||||
period: "/month",
|
period: "/mo",
|
||||||
apps: "100",
|
apps: "100",
|
||||||
ai: "100",
|
badge: "Popular",
|
||||||
badge: "Most Popular",
|
|
||||||
highlight: true,
|
highlight: true,
|
||||||
features: ["100 AI job applications/month", "100 AI resume customizations/month", "Application tracker", "Add your own API keys", "Email notifications", "Interview prep tips"],
|
features: ["100 AI job applications/month", "100 AI resume customizations/month", "Application tracker", "Add your own API keys", "Email notifications"],
|
||||||
cta: "Go Pro",
|
cta: "Go Pro",
|
||||||
ctaStyle: "bg-blue-500 hover:bg-blue-600"
|
ctaStyle: "bg-blue-500 hover:bg-blue-600"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Ultra",
|
name: "Ultra",
|
||||||
price: "$69",
|
price: "$69",
|
||||||
period: "/month",
|
period: "/mo",
|
||||||
apps: "200",
|
apps: "200",
|
||||||
ai: "200",
|
|
||||||
badge: "",
|
badge: "",
|
||||||
highlight: false,
|
highlight: false,
|
||||||
features: ["200 AI job applications/month", "200 AI resume customizations/month", "Priority processing", "Add your own API keys", "Email + SMS notifications"],
|
features: ["200 AI job applications/month", "200 AI resume customizations/month", "Priority processing", "Email + SMS notifications"],
|
||||||
cta: "Go Ultra",
|
cta: "Go Ultra",
|
||||||
ctaStyle: "bg-slate-600 hover:bg-slate-500"
|
ctaStyle: "bg-slate-600 hover:bg-slate-500"
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const agencyPlans = [
|
||||||
|
{
|
||||||
|
name: "Starter",
|
||||||
|
price: "$555",
|
||||||
|
period: "/mo",
|
||||||
|
submissions: "1,000",
|
||||||
|
clients: "10",
|
||||||
|
badge: "",
|
||||||
|
highlight: false,
|
||||||
|
features: ["1,000 job submissions/month", "Up to 10 client profiles", "AI resume tailoring", "White-label dashboard", "Priority support"],
|
||||||
|
cta: "Start Agency",
|
||||||
|
ctaStyle: "bg-purple-600 hover:bg-purple-500"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Growth",
|
||||||
|
price: "$999",
|
||||||
|
period: "/mo",
|
||||||
|
submissions: "3,000",
|
||||||
|
clients: "50",
|
||||||
|
badge: "",
|
||||||
|
highlight: true,
|
||||||
|
features: ["3,000 job submissions/month", "Up to 50 client profiles", "AI resume tailoring", "White-label dashboard", "Priority support"],
|
||||||
|
cta: "Grow Agency",
|
||||||
|
ctaStyle: "bg-purple-600 hover:bg-purple-500"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Scale",
|
||||||
|
price: "$1,499",
|
||||||
|
period: "/mo",
|
||||||
|
submissions: "5,000",
|
||||||
|
clients: "150",
|
||||||
|
badge: "",
|
||||||
|
highlight: false,
|
||||||
|
features: ["5,000 job submissions/month", "Up to 150 client profiles", "AI resume tailoring", "White-label dashboard", "Dedicated account manager"],
|
||||||
|
cta: "Scale Up",
|
||||||
|
ctaStyle: "bg-slate-600 hover:bg-slate-500"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Enterprise",
|
||||||
|
price: "$2,222",
|
||||||
|
period: "/mo",
|
||||||
|
submissions: "10,000",
|
||||||
|
clients: "500",
|
||||||
|
badge: "",
|
||||||
|
highlight: false,
|
||||||
|
features: ["10,000 job submissions/month", "Up to 500 client profiles", "AI resume tailoring", "White-label dashboard", "Dedicated account manager", "Custom integrations"],
|
||||||
|
cta: "Get Enterprise",
|
||||||
|
ctaStyle: "bg-slate-600 hover:bg-slate-500"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
export default function LandingPage() {
|
export default function LandingPage() {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-gradient-to-br from-slate-900 via-blue-950 to-slate-900">
|
<div className="min-h-screen bg-gradient-to-br from-slate-900 via-blue-950 to-slate-900">
|
||||||
@@ -90,12 +137,6 @@ export default function LandingPage() {
|
|||||||
>
|
>
|
||||||
Start Free — 5 Applications
|
Start Free — 5 Applications
|
||||||
</Link>
|
</Link>
|
||||||
<Link
|
|
||||||
href="/autojobs/pricing"
|
|
||||||
className="px-10 py-4 bg-white/10 hover:bg-white/20 text-white rounded-xl font-semibold text-lg border border-white/20 transition"
|
|
||||||
>
|
|
||||||
View All Plans
|
|
||||||
</Link>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -104,23 +145,22 @@ export default function LandingPage() {
|
|||||||
<section className="py-20 px-6 bg-slate-800/40">
|
<section className="py-20 px-6 bg-slate-800/40">
|
||||||
<div className="max-w-5xl mx-auto">
|
<div className="max-w-5xl mx-auto">
|
||||||
<h2 className="text-3xl font-bold text-white text-center mb-4">How AutoJobs Works</h2>
|
<h2 className="text-3xl font-bold text-white text-center mb-4">How AutoJobs Works</h2>
|
||||||
<p className="text-slate-400 text-center mb-12 max-w-xl mx-auto">Three steps to never manually applying to a job again.</p>
|
|
||||||
<div className="grid md:grid-cols-3 gap-8">
|
<div className="grid md:grid-cols-3 gap-8">
|
||||||
{[
|
{[
|
||||||
{
|
{
|
||||||
step: "01",
|
step: "01",
|
||||||
title: "Create Your Profile",
|
title: "Create Your Profile",
|
||||||
desc: "Upload your resume. Tell us what jobs you want — keywords, location, salary range. Add your own API keys for job search engines."
|
desc: "Upload your resume. Tell us what jobs you want — keywords, location, salary range."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
step: "02",
|
step: "02",
|
||||||
title: "AI Finds & Customizes",
|
title: "AI Finds & Customizes",
|
||||||
desc: "We search Jooble, JSearch, and more. For each match, AI rewrites your resume and writes a personalized cover letter targeting that company."
|
desc: "We search Jooble, JSearch, and more. AI rewrites your resume and writes cover letters."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
step: "03",
|
step: "03",
|
||||||
title: "Apply & Track",
|
title: "Apply & Track",
|
||||||
desc: "Apply with one click. Track every application status — applied, interviewing, offer, rejected. Land more interviews."
|
desc: "Apply with one click. Track every application status — from applied to offer."
|
||||||
}
|
}
|
||||||
].map((item) => (
|
].map((item) => (
|
||||||
<div key={item.step} className="relative bg-slate-700/50 rounded-2xl p-8 border border-slate-600 hover:border-blue-500/50 transition">
|
<div key={item.step} className="relative bg-slate-700/50 rounded-2xl p-8 border border-slate-600 hover:border-blue-500/50 transition">
|
||||||
@@ -133,40 +173,14 @@ export default function LandingPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Features Grid */}
|
{/* Jobseeker Pricing */}
|
||||||
<section className="py-20 px-6">
|
<section className="py-20 px-6">
|
||||||
<div className="max-w-5xl mx-auto">
|
|
||||||
<h2 className="text-3xl font-bold text-white text-center mb-12">Everything You Need to Land the Job</h2>
|
|
||||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
||||||
{[
|
|
||||||
{ icon: "🎯", title: "AI Resume Tailoring", desc: "Every resume is rewritten to match the exact job description and keywords" },
|
|
||||||
{ icon: "✉️", title: "AI Cover Letters", desc: "Personalized for each company — their mission, news, and your fit" },
|
|
||||||
{ icon: "🔍", title: "Multi-Source Search", desc: "Jooble, JSearch, and more — aggregated and deduplicated" },
|
|
||||||
{ icon: "📊", title: "Application Tracker", desc: "Dashboard shows every application, status, interview invites" },
|
|
||||||
{ icon: "🔑", title: "Your Own API Keys", desc: "Add your own keys — you control your data and spending" },
|
|
||||||
{ icon: "⚡", title: "Apply While You Sleep", desc: "AI works 24/7. Wake up to new opportunities submitted" },
|
|
||||||
{ icon: "📱", title: "Mobile Dashboard", desc: "Track your applications from anywhere — phone, tablet, desktop" },
|
|
||||||
{ icon: "📈", title: "Usage Analytics", desc: "See how many applications you've sent this month" },
|
|
||||||
{ icon: "🔒", title: "Private & Secure", desc: "Your data stays yours. API keys are encrypted." },
|
|
||||||
].map((f) => (
|
|
||||||
<div key={f.title} className="bg-slate-800/50 rounded-xl p-5 border border-slate-700 hover:border-slate-500 transition">
|
|
||||||
<div className="text-2xl mb-3">{f.icon}</div>
|
|
||||||
<h3 className="text-lg font-semibold text-white mb-1">{f.title}</h3>
|
|
||||||
<p className="text-slate-400 text-sm">{f.desc}</p>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* Pricing */}
|
|
||||||
<section className="py-20 px-6 bg-slate-800/40">
|
|
||||||
<div className="max-w-6xl mx-auto text-center">
|
<div className="max-w-6xl mx-auto text-center">
|
||||||
<h2 className="text-3xl font-bold text-white mb-4">Simple, Transparent Pricing</h2>
|
<h2 className="text-3xl font-bold text-white mb-4">For Job Seekers</h2>
|
||||||
<p className="text-slate-400 mb-12">Pick the plan that fits your job search. No hidden fees.</p>
|
<p className="text-slate-400 mb-12">Pick the plan that fits your job search.</p>
|
||||||
|
|
||||||
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-6 max-w-5xl mx-auto" style={{gridTemplateColumns: 'repeat(4, 1fr)'}}>
|
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-6 max-w-5xl mx-auto">
|
||||||
{plans.map((plan) => (
|
{jobseekerPlans.map((plan) => (
|
||||||
<div
|
<div
|
||||||
key={plan.name}
|
key={plan.name}
|
||||||
className={`rounded-2xl p-6 border text-left relative ${
|
className={`rounded-2xl p-6 border text-left relative ${
|
||||||
@@ -187,9 +201,7 @@ export default function LandingPage() {
|
|||||||
<span className="text-3xl font-bold text-white">{plan.price}</span>
|
<span className="text-3xl font-bold text-white">{plan.price}</span>
|
||||||
<span className="text-slate-400 text-sm">{plan.period}</span>
|
<span className="text-slate-400 text-sm">{plan.period}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-slate-500 mb-4">
|
<div className="text-xs text-blue-400 mb-4">{plan.apps} apps + AI customizations/mo</div>
|
||||||
{plan.apps} applications + {plan.ai} AI customizations/month
|
|
||||||
</div>
|
|
||||||
<ul className="space-y-2 mb-6">
|
<ul className="space-y-2 mb-6">
|
||||||
{plan.features.map((f) => (
|
{plan.features.map((f) => (
|
||||||
<li key={f} className="text-slate-300 text-sm flex items-start gap-2">
|
<li key={f} className="text-slate-300 text-sm flex items-start gap-2">
|
||||||
@@ -206,9 +218,60 @@ export default function LandingPage() {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
<div className="mt-8 text-slate-400 text-sm">
|
{/* Agency Pricing */}
|
||||||
<p>Need more? <span className="text-blue-400">Business</span> (500/mo) = $119 | <span className="text-blue-400">Unlimited</span> = $319/month</p>
|
<section className="py-20 px-6 bg-slate-800/40">
|
||||||
|
<div className="max-w-6xl mx-auto text-center">
|
||||||
|
<div className="inline-block px-4 py-1.5 rounded-full bg-purple-500/20 border border-purple-500/30 text-purple-300 text-sm mb-4">
|
||||||
|
For Recruiting Agencies
|
||||||
|
</div>
|
||||||
|
<h2 className="text-3xl font-bold text-white mb-4">Agency Plans — Manage Multiple Clients</h2>
|
||||||
|
<p className="text-slate-400 mb-12">Run job applications for your entire client roster. Each plan includes client profile management and submission limits.</p>
|
||||||
|
|
||||||
|
<div className="grid md:grid-cols-2 lg:grid-cols-4 gap-6 max-w-5xl mx-auto">
|
||||||
|
{agencyPlans.map((plan) => (
|
||||||
|
<div
|
||||||
|
key={plan.name}
|
||||||
|
className={`rounded-2xl p-6 border text-left relative ${
|
||||||
|
plan.highlight
|
||||||
|
? 'bg-gradient-to-br from-purple-600/30 to-pink-600/30 border-purple-500/50 shadow-lg shadow-purple-500/10'
|
||||||
|
: 'bg-slate-700/50 border-slate-600'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{plan.badge && (
|
||||||
|
<div className="absolute -top-3 left-1/2 -translate-x-1/2">
|
||||||
|
<span className="px-3 py-1 bg-purple-500 text-white text-xs font-bold rounded-full">
|
||||||
|
{plan.badge}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="text-sm text-purple-400 font-medium mb-1">{plan.name}</div>
|
||||||
|
<div className="flex items-baseline gap-1 mb-1">
|
||||||
|
<span className="text-3xl font-bold text-white">{plan.price}</span>
|
||||||
|
<span className="text-slate-400 text-sm">{plan.period}</span>
|
||||||
|
</div>
|
||||||
|
<div className="text-xs text-slate-500 mb-4">{plan.submissions} submissions • {plan.clients} clients</div>
|
||||||
|
<ul className="space-y-2 mb-6">
|
||||||
|
{plan.features.map((f) => (
|
||||||
|
<li key={f} className="text-slate-300 text-sm flex items-start gap-2">
|
||||||
|
<span className="text-purple-400">✓</span> {f}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
<Link
|
||||||
|
href="/autojobs/signup?type=agency"
|
||||||
|
className={`block text-center px-4 py-2.5 rounded-lg font-medium text-white transition ${plan.ctaStyle}`}
|
||||||
|
>
|
||||||
|
{plan.cta}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-8 text-slate-500 text-sm">
|
||||||
|
<p>No unlimited agency plan — all submissions are capped to prevent abuse.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -216,17 +279,17 @@ export default function LandingPage() {
|
|||||||
{/* Stats */}
|
{/* Stats */}
|
||||||
<section className="py-16 px-6">
|
<section className="py-16 px-6">
|
||||||
<div className="max-w-4xl mx-auto grid grid-cols-3 gap-8 text-center">
|
<div className="max-w-4xl mx-auto grid grid-cols-3 gap-8 text-center">
|
||||||
<div>
|
|
||||||
<div className="text-3xl font-bold text-white mb-1">5</div>
|
|
||||||
<div className="text-slate-400 text-sm">Free applications/month</div>
|
|
||||||
</div>
|
|
||||||
<div>
|
<div>
|
||||||
<div className="text-3xl font-bold text-white mb-1"><$0.01</div>
|
<div className="text-3xl font-bold text-white mb-1"><$0.01</div>
|
||||||
<div className="text-slate-400 text-sm">Cost per AI customization</div>
|
<div className="text-slate-400 text-sm">Cost per application</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div className="text-3xl font-bold text-white mb-1">15-25s</div>
|
<div className="text-3xl font-bold text-white mb-1">15-25s</div>
|
||||||
<div className="text-slate-400 text-sm">AI time per application</div>
|
<div className="text-slate-400 text-sm">AI time per job customization</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="text-3xl font-bold text-white mb-1">500+</div>
|
||||||
|
<div className="text-slate-400 text-sm">Jobs found per search</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
Reference in New Issue
Block a user