feat: rebrand application from Padel Pro to SmashPoint

Complete rename across all layers: UI branding, package names
(@smashpoint/web, @smashpoint/shared), infrastructure (Docker,
DB config), seed data, documentation, and logo/favicon.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Ivan
2026-02-08 02:46:29 +00:00
parent 242b8bad3d
commit 45ceeba9e3
27 changed files with 152 additions and 147 deletions

View File

@@ -1,4 +1,4 @@
DATABASE_URL="postgresql://user:password@localhost:5432/padel_pro?schema=public"
DATABASE_URL="postgresql://user:password@localhost:5432/smashpoint_db?schema=public"
NEXTAUTH_SECRET="your-secret-key-here"
NEXTAUTH_URL="http://localhost:3000"
NEXT_PUBLIC_APP_URL="http://localhost:3000"

View File

@@ -55,8 +55,8 @@ export default function SettingsPage() {
const [message, setMessage] = useState<{ type: "success" | "error"; text: string } | null>(null);
// Organization state
const [orgName, setOrgName] = useState("Padel Pro Demo");
const [orgEmail, setOrgEmail] = useState("info@padelpro.com");
const [orgName, setOrgName] = useState("SmashPoint Demo");
const [orgEmail, setOrgEmail] = useState("info@smashpoint.com");
const [orgPhone, setOrgPhone] = useState("+52 555 123 4567");
const [currency, setCurrency] = useState("MXN");
const [timezone, setTimezone] = useState("America/Mexico_City");

View File

@@ -11,29 +11,20 @@ function LoginContent() {
<div className="max-w-md text-center">
{/* Logo */}
<div className="mb-8 flex justify-center">
<div className="w-24 h-24 bg-white/10 backdrop-blur-sm rounded-2xl flex items-center justify-center border border-white/20">
<svg
viewBox="0 0 100 100"
className="w-16 h-16 text-white"
fill="currentColor"
>
{/* Padel racket stylized icon */}
<ellipse cx="50" cy="40" rx="28" ry="35" fill="none" stroke="currentColor" strokeWidth="4" />
<line x1="50" y1="75" x2="50" y2="95" stroke="currentColor" strokeWidth="6" strokeLinecap="round" />
<circle cx="35" cy="30" r="3" />
<circle cx="50" cy="25" r="3" />
<circle cx="65" cy="30" r="3" />
<circle cx="35" cy="45" r="3" />
<circle cx="50" cy="40" r="3" />
<circle cx="65" cy="45" r="3" />
<circle cx="42" cy="55" r="3" />
<circle cx="58" cy="55" r="3" />
<div className="w-24 h-24 bg-amber-500/20 backdrop-blur-sm rounded-2xl flex items-center justify-center border border-amber-400/30">
<svg viewBox="0 0 100 100" className="w-16 h-16" fill="none">
{/* Lightning bolt / smash icon */}
<path d="M55 10L20 55h25l-10 35L70 45H45l10-35z" fill="#FBBF24" />
{/* Impact sparks */}
<circle cx="78" cy="18" r="4" fill="#FBBF24" opacity="0.8" />
<circle cx="85" cy="28" r="2.5" fill="#FBBF24" opacity="0.6" />
<circle cx="72" cy="10" r="2" fill="#FBBF24" opacity="0.5" />
</svg>
</div>
</div>
{/* Title */}
<h1 className="text-4xl font-bold mb-4">Padel Pro</h1>
<h1 className="text-4xl font-bold mb-4">SmashPoint</h1>
{/* Tagline */}
<p className="text-xl text-primary-200 mb-8">
@@ -104,25 +95,15 @@ function LoginContent() {
<div className="w-full lg:w-1/2 flex flex-col justify-center items-center p-6 lg:p-12">
{/* Mobile Logo */}
<div className="lg:hidden mb-8 text-center text-white">
<div className="w-16 h-16 mx-auto mb-4 bg-white/10 backdrop-blur-sm rounded-xl flex items-center justify-center border border-white/20">
<svg
viewBox="0 0 100 100"
className="w-10 h-10 text-white"
fill="currentColor"
>
<ellipse cx="50" cy="40" rx="28" ry="35" fill="none" stroke="currentColor" strokeWidth="4" />
<line x1="50" y1="75" x2="50" y2="95" stroke="currentColor" strokeWidth="6" strokeLinecap="round" />
<circle cx="35" cy="30" r="3" />
<circle cx="50" cy="25" r="3" />
<circle cx="65" cy="30" r="3" />
<circle cx="35" cy="45" r="3" />
<circle cx="50" cy="40" r="3" />
<circle cx="65" cy="45" r="3" />
<circle cx="42" cy="55" r="3" />
<circle cx="58" cy="55" r="3" />
<div className="w-16 h-16 mx-auto mb-4 bg-amber-500/20 backdrop-blur-sm rounded-xl flex items-center justify-center border border-amber-400/30">
<svg viewBox="0 0 100 100" className="w-10 h-10" fill="none">
<path d="M55 10L20 55h25l-10 35L70 45H45l10-35z" fill="#FBBF24" />
<circle cx="78" cy="18" r="4" fill="#FBBF24" opacity="0.8" />
<circle cx="85" cy="28" r="2.5" fill="#FBBF24" opacity="0.6" />
<circle cx="72" cy="10" r="2" fill="#FBBF24" opacity="0.5" />
</svg>
</div>
<h1 className="text-2xl font-bold">Padel Pro</h1>
<h1 className="text-2xl font-bold">SmashPoint</h1>
<p className="text-sm text-primary-200 mt-1">Sistema de Gestion para Clubes de Padel</p>
</div>
@@ -130,7 +111,7 @@ function LoginContent() {
{/* Footer */}
<p className="mt-8 text-center text-sm text-primary-300">
&copy; {new Date().getFullYear()} Padel Pro. Todos los derechos reservados.
&copy; {new Date().getFullYear()} SmashPoint. Todos los derechos reservados.
</p>
</div>
</div>

View File

@@ -2,7 +2,7 @@ import { NextRequest, NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import { db } from '@/lib/db';
import { createBookingSchema } from '@padel-pro/shared';
import { createBookingSchema } from '@smashpoint/shared';
import { Decimal } from '@prisma/client/runtime/library';
// Helper function to check if a time is premium (after 18:00 or weekend)

View File

@@ -2,7 +2,7 @@ import { NextRequest, NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from '@/lib/auth';
import { db } from '@/lib/db';
import { createClientSchema } from '@padel-pro/shared';
import { createClientSchema } from '@smashpoint/shared';
// GET /api/clients - List/search clients
export async function GET(request: NextRequest) {

6
apps/web/app/icon.svg Normal file
View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" fill="none">
<rect width="32" height="32" rx="8" fill="#F59E0B"/>
<path d="M17.5 3L6.5 17h8l-3 12L22.5 15H14.5l3-12z" fill="white"/>
<circle cx="25" cy="6" r="1.5" fill="white" opacity="0.8"/>
<circle cx="27" cy="9" r="1" fill="white" opacity="0.6"/>
</svg>

After

Width:  |  Height:  |  Size: 326 B

View File

@@ -5,10 +5,10 @@ import "./globals.css";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "Padel Pro",
title: "SmashPoint",
description: "Sistema de Gestión para Clubes de Pádel",
keywords: ["padel", "club", "reservas", "gestión", "deportes"],
authors: [{ name: "Padel Pro Team" }],
authors: [{ name: "SmashPoint Team" }],
};
export default function RootLayout({

View File

@@ -4,8 +4,19 @@ export default function Home() {
return (
<main className="min-h-screen flex flex-col items-center justify-center bg-gradient-to-br from-primary-50 to-primary-100">
<div className="text-center space-y-8 px-4">
{/* Logo */}
<div className="flex justify-center">
<div className="w-20 h-20 bg-amber-500 rounded-2xl flex items-center justify-center shadow-lg">
<svg viewBox="0 0 40 40" className="w-12 h-12 text-white" fill="none">
<path d="M22 4L8 22h10l-4 14L28 18H18l4-14z" fill="currentColor" />
<circle cx="32" cy="8" r="2" fill="currentColor" opacity="0.8" />
<circle cx="35" cy="12" r="1.2" fill="currentColor" opacity="0.6" />
<circle cx="30" cy="4" r="1" fill="currentColor" opacity="0.5" />
</svg>
</div>
</div>
<h1 className="text-5xl md:text-6xl font-bold text-primary-800">
Padel Pro
SmashPoint
</h1>
<p className="text-xl md:text-2xl text-primary-600 max-w-2xl mx-auto">
Sistema de Gestion para Clubes de Padel

View File

@@ -38,10 +38,17 @@ export function Sidebar() {
<aside className="fixed left-0 top-0 z-40 h-screen w-64 border-r border-primary-200 bg-white">
{/* Logo Section */}
<div className="flex h-16 items-center gap-3 border-b border-primary-200 px-6">
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-primary text-white font-bold text-lg">
P
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-amber-500">
<svg viewBox="0 0 40 40" className="w-7 h-7 text-white" fill="none">
{/* Lightning bolt / smash icon */}
<path d="M22 4L8 22h10l-4 14L28 18H18l4-14z" fill="currentColor" />
{/* Impact spark */}
<circle cx="32" cy="8" r="2" fill="currentColor" opacity="0.8" />
<circle cx="35" cy="12" r="1.2" fill="currentColor" opacity="0.6" />
<circle cx="30" cy="4" r="1" fill="currentColor" opacity="0.5" />
</svg>
</div>
<span className="text-xl font-semibold text-primary-800">Padel Pro</span>
<span className="text-xl font-semibold text-primary-800">SmashPoint</span>
</div>
{/* Navigation */}

View File

@@ -1,7 +1,7 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "standalone",
transpilePackages: ["@padel-pro/shared"],
transpilePackages: ["@smashpoint/shared"],
images: {
remotePatterns: [
{ protocol: "https", hostname: "res.cloudinary.com" },

View File

@@ -1,11 +1,11 @@
{
"name": "@padel-pro/web",
"name": "@smashpoint/web",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@padel-pro/web",
"name": "@smashpoint/web",
"version": "0.1.0",
"dependencies": {
"@prisma/client": "^5.10.0",

View File

@@ -1,5 +1,5 @@
{
"name": "@padel-pro/web",
"name": "@smashpoint/web",
"version": "0.1.0",
"private": true,
"scripts": {
@@ -14,7 +14,7 @@
"db:seed": "tsx prisma/seed.ts"
},
"dependencies": {
"@padel-pro/shared": "*",
"@smashpoint/shared": "*",
"@prisma/client": "^5.10.0",
"@radix-ui/react-dialog": "^1.0.5",
"@radix-ui/react-dropdown-menu": "^2.0.6",

View File

@@ -40,8 +40,8 @@ async function main() {
const organization = await prisma.organization.create({
data: {
name: 'Padel Pro Demo',
slug: 'padel-pro-demo',
name: 'SmashPoint Demo',
slug: 'smashpoint-demo',
settings: {
currency: 'MXN',
timezone: 'America/Mexico_City',
@@ -64,7 +64,7 @@ async function main() {
slug: 'sede-norte',
address: 'Av. Universidad 1000, Col. Del Valle',
phone: '+52 55 1234 5678',
email: 'norte@padelpro.com',
email: 'norte@smashpoint.com',
timezone: 'America/Mexico_City',
openTime: '07:00',
closeTime: '23:00',
@@ -74,7 +74,7 @@ async function main() {
slug: 'sede-sur',
address: 'Av. Insurgentes 2000, Col. Roma',
phone: '+52 55 2345 6789',
email: 'sur@padelpro.com',
email: 'sur@smashpoint.com',
timezone: 'America/Mexico_City',
openTime: '08:00',
closeTime: '22:00',
@@ -84,7 +84,7 @@ async function main() {
slug: 'sede-centro',
address: 'Calle Reforma 500, Centro Historico',
phone: '+52 55 3456 7890',
email: 'centro@padelpro.com',
email: 'centro@smashpoint.com',
timezone: 'America/Mexico_City',
openTime: '06:00',
closeTime: '24:00',
@@ -159,7 +159,7 @@ async function main() {
const adminUser = await prisma.user.create({
data: {
organizationId: organization.id,
email: 'admin@padelpro.com',
email: 'admin@smashpoint.com',
password: hashedPassword,
firstName: 'Administrador',
lastName: 'Sistema',
@@ -175,9 +175,9 @@ async function main() {
// SITE ADMINS (one per site)
// =============================================================================
const siteAdminsData = [
{ email: 'norte@padelpro.com', firstName: 'Carlos', lastName: 'Rodriguez', site: sites[0] },
{ email: 'sur@padelpro.com', firstName: 'Maria', lastName: 'Gonzalez', site: sites[1] },
{ email: 'centro@padelpro.com', firstName: 'Luis', lastName: 'Hernandez', site: sites[2] },
{ email: 'norte@smashpoint.com', firstName: 'Carlos', lastName: 'Rodriguez', site: sites[0] },
{ email: 'sur@smashpoint.com', firstName: 'Maria', lastName: 'Gonzalez', site: sites[1] },
{ email: 'centro@smashpoint.com', firstName: 'Luis', lastName: 'Hernandez', site: sites[2] },
];
for (const adminData of siteAdminsData) {
@@ -434,8 +434,8 @@ async function main() {
console.log(` - 1 Active Membership`);
console.log('');
console.log('Login credentials:');
console.log(' Super Admin: admin@padelpro.com / admin123');
console.log(' Site Admins: norte@padelpro.com, sur@padelpro.com, centro@padelpro.com / admin123');
console.log(' Super Admin: admin@smashpoint.com / admin123');
console.log(' Site Admins: norte@smashpoint.com, sur@smashpoint.com, centro@smashpoint.com / admin123');
console.log('');
}

BIN
apps/web/public/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB