SEO landing page
This commit is contained in:
parent
3ac7102501
commit
669646aacb
|
|
@ -1,211 +0,0 @@
|
|||
[
|
||||
{
|
||||
"title": "Padel / Sport",
|
||||
"priority": 10,
|
||||
"rules_json": "{\"or\":[{\"in\":[\"PLAYTOMIC\",{\"var\":\"description\"}]},{\"in\":[\"M3 SPORT\",{\"var\":\"description\"}]},{\"in\":[\"Padel\",{\"var\":\"description\"}]}]}",
|
||||
"action_category_id": 99,
|
||||
"action_note": null,
|
||||
"action_note_iv": null,
|
||||
"category": {
|
||||
"name": "Sport and sports goods"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Gym / Sport",
|
||||
"priority": 10,
|
||||
"rules_json": "{\"in\":[\"Wellhub\",{\"var\":\"description\"}]}",
|
||||
"action_category_id": 99,
|
||||
"action_note": null,
|
||||
"action_note_iv": null,
|
||||
"category": {
|
||||
"name": "Sport and sports goods"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Rent income and expenses",
|
||||
"priority": 10,
|
||||
"rules_json": "{\"or\":[{\"in\":[\"MARIAM NAFEE\",{\"var\":\"description\"}]},{\"in\":[\"san pantaleon 3\",{\"var\":\"description\"}]},{\"in\":[\"bbva allianz seguros\",{\"var\":\"description\"}]},{\"in\":[\"Adeudo satec s.a.\",{\"var\":\"description\"}]}]}",
|
||||
"action_category_id": 129,
|
||||
"action_note": null,
|
||||
"action_note_iv": null,
|
||||
"category": {
|
||||
"name": "Income from rent"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Fuel",
|
||||
"priority": 10,
|
||||
"rules_json": "{\"in\":[\"REPSOL WAYLET\",{\"var\":\"description\"}]}",
|
||||
"action_category_id": 91,
|
||||
"action_note": null,
|
||||
"action_note_iv": null,
|
||||
"category": {
|
||||
"name": "Fuel"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Groceries",
|
||||
"priority": 10,
|
||||
"rules_json": "{\"or\":[{\"in\":[\"WAYLET ALBOLOTE ES\",{\"var\":\"description\"}]},{\"in\":[\"SQRUPS\",{\"var\":\"description\"}]},{\"in\":[\"MERCADONA\",{\"var\":\"description\"}]}]}",
|
||||
"action_category_id": 77,
|
||||
"action_note": null,
|
||||
"action_note_iv": null,
|
||||
"category": {
|
||||
"name": "Groceries"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Online expenses",
|
||||
"priority": 10,
|
||||
"rules_json": "{\"or\":[{\"or\":[{\"in\":[\"T3 CHAT\",{\"var\":\"description\"}]},{\"in\":[\"Google CLOUD\",{\"var\":\"description\"}]},{\"in\":[\"AWS\",{\"var\":\"description\"}]},{\"in\":[\"YouTubePremium\",{\"var\":\"description\"}]},{\"in\":[\"LARAVEL FORGE\",{\"var\":\"description\"}]},{\"in\":[\"CLAUDE.AI\",{\"var\":\"description\"}]},{\"in\":[\"DIGITALOCEAN.COM\",{\"var\":\"description\"}]},{\"in\":[\"REDDIT INC ADS\",{\"var\":\"description\"}]},{\"in\":[\"Amazon Prime\",{\"var\":\"description\"}]}]},{\"and\":[{\"in\":[\"Bizum\",{\"var\":\"description\"}]},{\"==\":[{\"var\":\"amount\"},13]}]}]}",
|
||||
"action_category_id": 107,
|
||||
"action_note": null,
|
||||
"action_note_iv": null,
|
||||
"category": {
|
||||
"name": "Online services"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Traveling",
|
||||
"priority": 10,
|
||||
"rules_json": "{\"in\":[\"IBERIAEXPR\",{\"var\":\"description\"}]}",
|
||||
"action_category_id": 95,
|
||||
"action_note": null,
|
||||
"action_note_iv": null,
|
||||
"category": {
|
||||
"name": "Leisure activities, traveling"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Food delivery",
|
||||
"priority": 10,
|
||||
"rules_json": "{\"in\":[\"UBER *EATS\",{\"var\":\"description\"}]}",
|
||||
"action_category_id": 80,
|
||||
"action_note": null,
|
||||
"action_note_iv": null,
|
||||
"category": {
|
||||
"name": "Food delivery"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Own account movements",
|
||||
"priority": 10,
|
||||
"rules_json": "{\"and\":[{\"==\":[{\"var\":\"description\"},\"Transferencia recibida de VICTOR FALCON RUIZ\"]},{\"in\":[\"VICTOR FALCON RUIZ Own account\",{\"var\":\"description\"}]}]}",
|
||||
"action_category_id": 133,
|
||||
"action_note": null,
|
||||
"action_note_iv": null,
|
||||
"category": {
|
||||
"name": "Own account"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Indexa / Investments",
|
||||
"priority": 10,
|
||||
"rules_json": "{\"and\":[{\"==\":[{\"var\":\"description\"},\"Transferencia realizada\"]},{\"or\":[{\"==\":[{\"var\":\"amount\"},-575]},{\"==\":[{\"var\":\"amount\"},-500]}]}]}",
|
||||
"action_category_id": 109,
|
||||
"action_note": null,
|
||||
"action_note_iv": null,
|
||||
"category": {
|
||||
"name": "Investments"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Savings",
|
||||
"priority": 10,
|
||||
"rules_json": "{\"or\":[{\"in\":[\"VICTOR FALCON RUIZ Savings\",{\"var\":\"description\"}]},{\"and\":[{\"in\":[\"Transferencia realizada\",{\"var\":\"description\"}]},{\"==\":[{\"var\":\"amount\"},-750]}]}]}",
|
||||
"action_category_id": 110,
|
||||
"action_note": null,
|
||||
"action_note_iv": null,
|
||||
"category": {
|
||||
"name": "Savings"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "ISP / Utilities and internet",
|
||||
"priority": 10,
|
||||
"rules_json": "{\"in\":[\"digi spain telecom\",{\"var\":\"description\"}]}",
|
||||
"action_category_id": 85,
|
||||
"action_note": null,
|
||||
"action_note_iv": null,
|
||||
"category": {
|
||||
"name": "Telephone, internet, TV, computer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Farmacia",
|
||||
"priority": 10,
|
||||
"rules_json": "{\"in\":[\"Pago en FCIA.\",{\"var\":\"description\"}]}",
|
||||
"action_category_id": 105,
|
||||
"action_note": null,
|
||||
"action_note_iv": null,
|
||||
"category": {
|
||||
"name": "Health and pharmaceuticals"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Taxes",
|
||||
"priority": 10,
|
||||
"rules_json": "{\"or\":[{\"in\":[\"internetmadrid es\",{\"var\":\"description\"}]},{\"==\":[{\"var\":\"description\"},\"Ay ciudad real ciudad real es\"]},{\"in\":[\"Pago de impuestos\",{\"var\":\"description\"}]},{\"in\":[\"PAGO TRIBUTOS BARCELONA\",{\"var\":\"description\"}]}]}",
|
||||
"action_category_id": 119,
|
||||
"action_note": null,
|
||||
"action_note_iv": null,
|
||||
"category": {
|
||||
"name": "Taxes and government fees"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Payroll",
|
||||
"priority": 10,
|
||||
"rules_json": "{\"in\":[\"nómina\",{\"var\":\"description\"}]}",
|
||||
"action_category_id": 126,
|
||||
"action_note": null,
|
||||
"action_note_iv": null,
|
||||
"category": {
|
||||
"name": "Salary"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Restaurants",
|
||||
"priority": 10,
|
||||
"rules_json": "{\"in\":[\"GRANIER PACIFICO\",{\"var\":\"description\"}]}",
|
||||
"action_category_id": 76,
|
||||
"action_note": null,
|
||||
"action_note_iv": null,
|
||||
"category": {
|
||||
"name": "Cafes, restaurants, bars"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Mortage",
|
||||
"priority": 10,
|
||||
"rules_json": "{\"in\":[\"amortizacion de prestamo/credito\",{\"var\":\"description\"}]}",
|
||||
"action_category_id": 114,
|
||||
"action_note": null,
|
||||
"action_note_iv": null,
|
||||
"category": {
|
||||
"name": "Mortgage"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Credit Card",
|
||||
"priority": 10,
|
||||
"rules_json": "{\"in\":[\"mensual de tarjeta\",{\"var\":\"description\"}]}",
|
||||
"action_category_id": 115,
|
||||
"action_note": null,
|
||||
"action_note_iv": null,
|
||||
"category": {
|
||||
"name": "Credit card repayment"
|
||||
}
|
||||
},
|
||||
{
|
||||
"title": "Investments",
|
||||
"priority": 10,
|
||||
"rules_json": "{\"in\":[\"Adeudo indexa mas rentabilidad acciones f.p.\",{\"var\":\"description\"}]}",
|
||||
"action_category_id": 109,
|
||||
"action_note": null,
|
||||
"action_note_iv": null,
|
||||
"category": {
|
||||
"name": "Investments"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
@ -1,317 +0,0 @@
|
|||
[
|
||||
{
|
||||
"name": "Food",
|
||||
"icon": "Utensils",
|
||||
"color": "red"
|
||||
},
|
||||
{
|
||||
"name": "Cafes, restaurants, bars",
|
||||
"icon": "Wine",
|
||||
"color": "red"
|
||||
},
|
||||
{
|
||||
"name": "Groceries",
|
||||
"icon": "ShoppingBasket",
|
||||
"color": "red"
|
||||
},
|
||||
{
|
||||
"name": "Tobacco and alcohol",
|
||||
"icon": "Cigarette",
|
||||
"color": "red"
|
||||
},
|
||||
{
|
||||
"name": "Other groceries",
|
||||
"icon": "ShoppingBasket",
|
||||
"color": "red"
|
||||
},
|
||||
{
|
||||
"name": "Food delivery",
|
||||
"icon": "Pizza",
|
||||
"color": "red"
|
||||
},
|
||||
{
|
||||
"name": "Utility services",
|
||||
"icon": "Home",
|
||||
"color": "orange"
|
||||
},
|
||||
{
|
||||
"name": "Electricity",
|
||||
"icon": "Bolt",
|
||||
"color": "orange"
|
||||
},
|
||||
{
|
||||
"name": "Natural gas",
|
||||
"icon": "Flame",
|
||||
"color": "orange"
|
||||
},
|
||||
{
|
||||
"name": "Rent and maintanence",
|
||||
"icon": "Wrench",
|
||||
"color": "orange"
|
||||
},
|
||||
{
|
||||
"name": "Telephone, internet, TV, computer",
|
||||
"icon": "Wifi",
|
||||
"color": "orange"
|
||||
},
|
||||
{
|
||||
"name": "Water",
|
||||
"icon": "Droplets",
|
||||
"color": "orange"
|
||||
},
|
||||
{
|
||||
"name": "Other utility expenses",
|
||||
"icon": "Receipt",
|
||||
"color": "orange"
|
||||
},
|
||||
{
|
||||
"name": "Household goods",
|
||||
"icon": "Home",
|
||||
"color": "orange"
|
||||
},
|
||||
{
|
||||
"name": "Transportation",
|
||||
"icon": "Bus",
|
||||
"color": "amber"
|
||||
},
|
||||
{
|
||||
"name": "Parking",
|
||||
"icon": "ParkingMeter",
|
||||
"color": "amber"
|
||||
},
|
||||
{
|
||||
"name": "Fuel",
|
||||
"icon": "Fuel",
|
||||
"color": "amber"
|
||||
},
|
||||
{
|
||||
"name": "Transportation expenses",
|
||||
"icon": "Ticket",
|
||||
"color": "amber"
|
||||
},
|
||||
{
|
||||
"name": "Vehicle purchase, maintenance",
|
||||
"icon": "Car",
|
||||
"color": "amber"
|
||||
},
|
||||
{
|
||||
"name": "Clothing and shoes",
|
||||
"icon": "Shirt",
|
||||
"color": "pink"
|
||||
},
|
||||
{
|
||||
"name": "Leisure activities, traveling",
|
||||
"icon": "Plane",
|
||||
"color": "violet"
|
||||
},
|
||||
{
|
||||
"name": "Gifts",
|
||||
"icon": "Gift",
|
||||
"color": "violet"
|
||||
},
|
||||
{
|
||||
"name": "Books, newspapers, magazines",
|
||||
"icon": "BookOpen",
|
||||
"color": "violet"
|
||||
},
|
||||
{
|
||||
"name": "Accommodation, travel expenses",
|
||||
"icon": "Hotel",
|
||||
"color": "violet"
|
||||
},
|
||||
{
|
||||
"name": "Sport and sports goods",
|
||||
"icon": "Dumbbell",
|
||||
"color": "violet"
|
||||
},
|
||||
{
|
||||
"name": "Theatre, music, cinema",
|
||||
"icon": "Clapperboard",
|
||||
"color": "violet"
|
||||
},
|
||||
{
|
||||
"name": "Hobbies and other leisure time activites",
|
||||
"icon": "Puzzle",
|
||||
"color": "violet"
|
||||
},
|
||||
{
|
||||
"name": "Education, health and beauty",
|
||||
"icon": "GraduationCap",
|
||||
"color": "rose"
|
||||
},
|
||||
{
|
||||
"name": "Education and courses",
|
||||
"icon": "GraduationCap",
|
||||
"color": "rose"
|
||||
},
|
||||
{
|
||||
"name": "Beauty, cosmetics",
|
||||
"icon": "Sparkles",
|
||||
"color": "rose"
|
||||
},
|
||||
{
|
||||
"name": "Health and pharmaceuticals",
|
||||
"icon": "HeartPulse",
|
||||
"color": "rose"
|
||||
},
|
||||
{
|
||||
"name": "Online transactions",
|
||||
"icon": "Globe",
|
||||
"color": "fuchsia"
|
||||
},
|
||||
{
|
||||
"name": "Online services",
|
||||
"icon": "Server",
|
||||
"color": "fuchsia"
|
||||
},
|
||||
{
|
||||
"name": "Insurance",
|
||||
"icon": "ShieldCheck",
|
||||
"color": "yellow"
|
||||
},
|
||||
{
|
||||
"name": "Investments",
|
||||
"icon": "LineChart",
|
||||
"color": "lime"
|
||||
},
|
||||
{
|
||||
"name": "Savings",
|
||||
"icon": "PiggyBank",
|
||||
"color": "lime"
|
||||
},
|
||||
{
|
||||
"name": "Other investments",
|
||||
"icon": "TrendingUp",
|
||||
"color": "lime"
|
||||
},
|
||||
{
|
||||
"name": "Financial services and commission",
|
||||
"icon": "Landmark",
|
||||
"color": "slate"
|
||||
},
|
||||
{
|
||||
"name": "Fines",
|
||||
"icon": "Gavel",
|
||||
"color": "slate"
|
||||
},
|
||||
{
|
||||
"name": "Mortgage",
|
||||
"icon": "Building2",
|
||||
"color": "slate"
|
||||
},
|
||||
{
|
||||
"name": "Credit card repayment",
|
||||
"icon": "CreditCard",
|
||||
"color": "slate"
|
||||
},
|
||||
{
|
||||
"name": "Cash withdrawal",
|
||||
"icon": "Banknote",
|
||||
"color": "neutral"
|
||||
},
|
||||
{
|
||||
"name": "Gambling",
|
||||
"icon": "Dice5",
|
||||
"color": "purple"
|
||||
},
|
||||
{
|
||||
"name": "Lottery",
|
||||
"icon": "TicketPercent",
|
||||
"color": "purple"
|
||||
},
|
||||
{
|
||||
"name": "Taxes and government fees",
|
||||
"icon": "FileText",
|
||||
"color": "stone"
|
||||
},
|
||||
{
|
||||
"name": "Invoices",
|
||||
"icon": "FileText",
|
||||
"color": "stone"
|
||||
},
|
||||
{
|
||||
"name": "Personal transfers",
|
||||
"icon": "ArrowLeftRight",
|
||||
"color": "cyan"
|
||||
},
|
||||
{
|
||||
"name": "Other personal transfers",
|
||||
"icon": "ArrowLeftRight",
|
||||
"color": "cyan"
|
||||
},
|
||||
{
|
||||
"name": "Administrative violations",
|
||||
"icon": "BadgeAlert",
|
||||
"color": "stone"
|
||||
},
|
||||
{
|
||||
"name": "Other transfers",
|
||||
"icon": "Split",
|
||||
"color": "stone"
|
||||
},
|
||||
{
|
||||
"name": "Other payments",
|
||||
"icon": "Wallet",
|
||||
"color": "stone"
|
||||
},
|
||||
{
|
||||
"name": "Salary",
|
||||
"icon": "Coins",
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"name": "Regular income",
|
||||
"icon": "Coins",
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"name": "Work on demand",
|
||||
"icon": "Briefcase",
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"name": "Income from rent",
|
||||
"icon": "Building",
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"name": "Unemployment benefit",
|
||||
"icon": "HandCoins",
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"name": "Tax return",
|
||||
"icon": "RotateCcw",
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"name": "Return debit",
|
||||
"icon": "Undo2",
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"name": "Own account",
|
||||
"icon": "ArrowRightLeft",
|
||||
"color": "blue"
|
||||
},
|
||||
{
|
||||
"name": "From account of relatives",
|
||||
"icon": "Users",
|
||||
"color": "blue"
|
||||
},
|
||||
{
|
||||
"name": "Returned payments",
|
||||
"icon": "RotateCw",
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"name": "Credit cards",
|
||||
"icon": "CreditCard",
|
||||
"color": "green"
|
||||
},
|
||||
{
|
||||
"name": "Other incoming payments",
|
||||
"icon": "DollarSign",
|
||||
"color": "green"
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class RobotsController extends Controller
|
||||
{
|
||||
public function index(): Response
|
||||
{
|
||||
$baseUrl = config('app.url');
|
||||
|
||||
$content = "User-agent: *\n";
|
||||
$content .= "Disallow: /api/\n";
|
||||
$content .= "Disallow: /dashboard\n";
|
||||
$content .= "Disallow: /setup-encryption\n";
|
||||
$content .= "Disallow: /transactions\n";
|
||||
$content .= "Disallow: /settings\n";
|
||||
$content .= "\n";
|
||||
$content .= "Sitemap: {$baseUrl}/sitemap.xml\n";
|
||||
|
||||
return response($content, 200)
|
||||
->header('Content-Type', 'text/plain');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Response;
|
||||
|
||||
class SitemapController extends Controller
|
||||
{
|
||||
public function index(): Response
|
||||
{
|
||||
$baseUrl = config('app.url');
|
||||
|
||||
$urls = [
|
||||
[
|
||||
'loc' => $baseUrl,
|
||||
'changefreq' => 'weekly',
|
||||
'priority' => '1.0',
|
||||
'lastmod' => now()->toW3cString(),
|
||||
],
|
||||
[
|
||||
'loc' => "{$baseUrl}/privacy",
|
||||
'changefreq' => 'monthly',
|
||||
'priority' => '0.5',
|
||||
'lastmod' => now()->toW3cString(),
|
||||
],
|
||||
[
|
||||
'loc' => "{$baseUrl}/terms",
|
||||
'changefreq' => 'monthly',
|
||||
'priority' => '0.5',
|
||||
'lastmod' => now()->toW3cString(),
|
||||
],
|
||||
];
|
||||
|
||||
$xml = '<?xml version="1.0" encoding="UTF-8"?>'."\n";
|
||||
$xml .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'."\n";
|
||||
|
||||
foreach ($urls as $url) {
|
||||
$xml .= ' <url>'."\n";
|
||||
$xml .= " <loc>{$url['loc']}</loc>\n";
|
||||
$xml .= " <lastmod>{$url['lastmod']}</lastmod>\n";
|
||||
$xml .= " <changefreq>{$url['changefreq']}</changefreq>\n";
|
||||
$xml .= " <priority>{$url['priority']}</priority>\n";
|
||||
$xml .= ' </url>'."\n";
|
||||
}
|
||||
|
||||
$xml .= '</urlset>';
|
||||
|
||||
return response($xml, 200)
|
||||
->header('Content-Type', 'application/xml');
|
||||
}
|
||||
}
|
||||
|
|
@ -41,6 +41,7 @@ class HandleInertiaRequests extends Middleware
|
|||
return [
|
||||
...parent::share($request),
|
||||
'name' => config('app.name'),
|
||||
'appUrl' => config('app.url'),
|
||||
'quote' => ['message' => trim($message), 'author' => trim($author)],
|
||||
'auth' => [
|
||||
'user' => $request->user(),
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 202 KiB |
|
|
@ -1,2 +0,0 @@
|
|||
User-agent: *
|
||||
Disallow:
|
||||
|
|
@ -1,13 +1,26 @@
|
|||
import { Head, Link } from '@inertiajs/react';
|
||||
import { Head, Link, usePage } from '@inertiajs/react';
|
||||
import { type SharedData } from '@/types';
|
||||
|
||||
export default function Privacy() {
|
||||
const { appUrl } = usePage<SharedData>().props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head title="Privacy Policy">
|
||||
<Head title="Privacy Policy - Whisper Money">
|
||||
<meta
|
||||
name="description"
|
||||
content="Our privacy policy outlines how we collect, use, and protect your personal information."
|
||||
content="Privacy policy for Whisper Money. Learn how we collect, use, and protect your personal information with end-to-end encryption."
|
||||
/>
|
||||
<link rel="canonical" href={`${appUrl}/privacy`} />
|
||||
<meta name="robots" content="index, follow" />
|
||||
|
||||
<meta property="og:title" content="Privacy Policy - Whisper Money" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Privacy policy for Whisper Money. Learn how we collect, use, and protect your personal information."
|
||||
/>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content={`${appUrl}/privacy`} />
|
||||
</Head>
|
||||
<div className="min-h-screen bg-[#FDFDFC] text-[#1b1b18] dark:bg-[#0a0a0a] dark:text-[#EDEDEC]">
|
||||
<div className="mx-auto max-w-4xl px-6 py-12 lg:px-8 lg:py-16">
|
||||
|
|
|
|||
|
|
@ -1,13 +1,26 @@
|
|||
import { Head, Link } from '@inertiajs/react';
|
||||
import { Head, Link, usePage } from '@inertiajs/react';
|
||||
import { type SharedData } from '@/types';
|
||||
|
||||
export default function Terms() {
|
||||
const { appUrl } = usePage<SharedData>().props;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Head title="Terms of Service">
|
||||
<Head title="Terms of Service - Whisper Money">
|
||||
<meta
|
||||
name="description"
|
||||
content="Our terms of service outline the rules and regulations for using our platform."
|
||||
content="Terms of service for Whisper Money. Review the rules and regulations for using our secure personal finance platform."
|
||||
/>
|
||||
<link rel="canonical" href={`${appUrl}/terms`} />
|
||||
<meta name="robots" content="index, follow" />
|
||||
|
||||
<meta property="og:title" content="Terms of Service - Whisper Money" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Terms of service for Whisper Money. Review the rules and regulations for using our platform."
|
||||
/>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content={`${appUrl}/terms`} />
|
||||
</Head>
|
||||
<div className="min-h-screen bg-[#FDFDFC] text-[#1b1b18] dark:bg-[#0a0a0a] dark:text-[#EDEDEC]">
|
||||
<div className="mx-auto max-w-4xl px-6 py-12 lg:px-8 lg:py-16">
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ export default function Welcome({
|
|||
canRegister?: boolean;
|
||||
hideAuthButtons?: boolean;
|
||||
}) {
|
||||
const { auth } = usePage<SharedData>().props;
|
||||
const { auth, appUrl } = usePage<SharedData>().props;
|
||||
const emailInputRef = useRef<HTMLInputElement>(null);
|
||||
const visitTrackedRef = useRef(false);
|
||||
|
||||
|
|
@ -44,25 +44,34 @@ export default function Welcome({
|
|||
|
||||
return (
|
||||
<>
|
||||
<Head title="Welcome">
|
||||
<Head title="Whisper Money - The Most Secure Personal Finance App">
|
||||
<meta
|
||||
name="description"
|
||||
content="The most secure personal finance app with end-to-end encryption. Track expenses, create budgets, and manage your money privately."
|
||||
/>
|
||||
<link rel="canonical" href={window.location.origin} />
|
||||
<meta
|
||||
name="keywords"
|
||||
content="finance app, budgeting, expense tracking, end-to-end encryption, secure finance, personal finance, money management, privacy, encrypted finance app"
|
||||
/>
|
||||
<link rel="canonical" href={appUrl} />
|
||||
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Google+Sans+Code:ital,wght@0,300..800;1,300..800&family=Stack+Sans+Text:wght@200..700&display=swap" rel="stylesheet" />
|
||||
|
||||
<meta property="og:site_name" content="Whisper Money" />
|
||||
<meta property="og:title" content="Whisper Money - The Most Secure Personal Finance App" />
|
||||
<meta
|
||||
property="og:description"
|
||||
content="Your financial data stays private with end-to-end encryption. The most secure way to manage your personal finances."
|
||||
/>
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:url" content={window.location.origin} />
|
||||
<meta property="og:image" content={`${window.location.origin}/og-image.png`} />
|
||||
<meta property="og:url" content={appUrl} />
|
||||
<meta property="og:image" content={`${appUrl}/images/og_whisper_money.png`} />
|
||||
<meta property="og:image:width" content="1200" />
|
||||
<meta property="og:image:height" content="630" />
|
||||
<meta property="og:image:alt" content="Whisper Money - Secure Personal Finance App" />
|
||||
<meta property="og:locale" content="en_US" />
|
||||
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Whisper Money - The Most Secure Personal Finance App" />
|
||||
|
|
@ -70,7 +79,32 @@ export default function Welcome({
|
|||
name="twitter:description"
|
||||
content="Your financial data stays private with end-to-end encryption. The most secure way to manage your personal finances."
|
||||
/>
|
||||
<meta name="twitter:image" content={`${window.location.origin}/og-image.png`} />
|
||||
<meta name="twitter:image" content={`${appUrl}/images/og_whisper_money.png`} />
|
||||
<meta name="twitter:image:alt" content="Whisper Money - Secure Personal Finance App" />
|
||||
|
||||
<script type="application/ld+json">
|
||||
{JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'WebApplication',
|
||||
name: 'Whisper Money',
|
||||
description: 'The most secure personal finance app with end-to-end encryption. Track expenses, create budgets, and manage your money privately.',
|
||||
url: appUrl,
|
||||
applicationCategory: 'FinanceApplication',
|
||||
offers: {
|
||||
'@type': 'Offer',
|
||||
price: '0',
|
||||
priceCurrency: 'USD',
|
||||
},
|
||||
featureList: [
|
||||
'End-to-end encryption',
|
||||
'Smart budgeting',
|
||||
'Expense tracking',
|
||||
'Visual insights',
|
||||
'Zero tracking',
|
||||
'Open source',
|
||||
],
|
||||
})}
|
||||
</script>
|
||||
</Head>
|
||||
<div className="flex min-h-screen flex-col bg-[#FDFDFC] text-[#1b1b18] dark:bg-[#0a0a0a] dark:text-[#EDEDEC]">
|
||||
<header className="w-full fade-bottom bg-background/5 fixed top-0 z-50 backdrop-blur-lg">
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ export interface NavItem {
|
|||
|
||||
export interface SharedData {
|
||||
name: string;
|
||||
appUrl: string;
|
||||
quote: { message: string; author: string };
|
||||
auth: Auth;
|
||||
sidebarOpen: boolean;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#1b1b18" media="(prefers-color-scheme: light)">
|
||||
<meta name="theme-color" content="#0a0a0a" media="(prefers-color-scheme: dark)">
|
||||
|
||||
{{-- Inline script to detect system dark mode preference and apply it immediately --}}
|
||||
<script>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
use App\Http\Controllers\AccountBalanceController;
|
||||
use App\Http\Controllers\EncryptionController;
|
||||
use App\Http\Controllers\RobotsController;
|
||||
use App\Http\Controllers\SitemapController;
|
||||
use App\Http\Controllers\Sync\AccountBalanceSyncController;
|
||||
use App\Http\Controllers\Sync\AccountSyncController;
|
||||
use App\Http\Controllers\Sync\BankSyncController;
|
||||
|
|
@ -19,6 +21,9 @@ Route::get('/', function () {
|
|||
]);
|
||||
})->name('home');
|
||||
|
||||
Route::get('sitemap.xml', [SitemapController::class, 'index'])->name('sitemap');
|
||||
Route::get('robots.txt', [RobotsController::class, 'index'])->name('robots');
|
||||
|
||||
Route::post('user-leads', [UserLeadController::class, 'store'])->name('user-leads.store');
|
||||
|
||||
Route::get('privacy', function () {
|
||||
|
|
|
|||
|
|
@ -23,3 +23,11 @@ test('authenticated users receive auth user in shared props', function () {
|
|||
->where('auth.user.email', $user->email)
|
||||
);
|
||||
});
|
||||
|
||||
test('all pages receive app url in shared props', function () {
|
||||
$response = $this->get(route('home'));
|
||||
|
||||
$response->assertInertia(fn (Assert $page) => $page
|
||||
->where('appUrl', config('app.url'))
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
test('sitemap returns valid xml', function () {
|
||||
$response = $this->get('/sitemap.xml');
|
||||
|
||||
$response->assertSuccessful();
|
||||
$response->assertHeader('Content-Type', 'application/xml');
|
||||
expect($response->content())->toContain('<?xml version="1.0" encoding="UTF-8"?>');
|
||||
expect($response->content())->toContain('<urlset');
|
||||
expect($response->content())->toContain(config('app.url'));
|
||||
});
|
||||
|
||||
test('sitemap includes homepage', function () {
|
||||
$response = $this->get('/sitemap.xml');
|
||||
|
||||
$response->assertSuccessful();
|
||||
expect($response->content())->toContain('<loc>'.config('app.url').'</loc>');
|
||||
});
|
||||
|
||||
test('sitemap includes privacy and terms pages', function () {
|
||||
$response = $this->get('/sitemap.xml');
|
||||
|
||||
$response->assertSuccessful();
|
||||
expect($response->content())->toContain('<loc>'.config('app.url').'/privacy</loc>');
|
||||
expect($response->content())->toContain('<loc>'.config('app.url').'/terms</loc>');
|
||||
});
|
||||
|
||||
test('robots txt returns valid content', function () {
|
||||
$response = $this->get('/robots.txt');
|
||||
|
||||
$response->assertSuccessful();
|
||||
expect($response->headers->get('Content-Type'))->toContain('text/plain');
|
||||
expect($response->content())->toContain('User-agent: *');
|
||||
expect($response->content())->toContain('Sitemap: '.config('app.url').'/sitemap.xml');
|
||||
});
|
||||
|
||||
test('robots txt disallows protected routes', function () {
|
||||
$response = $this->get('/robots.txt');
|
||||
|
||||
$response->assertSuccessful();
|
||||
expect($response->content())->toContain('Disallow: /api/');
|
||||
expect($response->content())->toContain('Disallow: /dashboard');
|
||||
expect($response->content())->toContain('Disallow: /setup-encryption');
|
||||
});
|
||||
Loading…
Reference in New Issue