From 448035ad60208bb9c0cb8c3db3669c67ef3cdac8 Mon Sep 17 00:00:00 2001 From: Ryan Salazar Date: Fri, 26 Jun 2026 21:12:17 -0400 Subject: [PATCH] feat: JTR branding + Pink Pulse community partner integration --- deploy/check-deploy-fail.py | 29 ++++++ deploy/check-deploy-fail2.py | 23 +++++ deploy/redeploy-v2.py | 41 ++++++++ public/partners/jtr-wordmark.svg | 11 +++ public/partners/pinkpulse-icon.svg | 56 +++++++++++ src/app/privacy/page.tsx | 8 +- src/app/profile/page.tsx | 3 + src/app/terms/page.tsx | 9 +- src/components/ChatPanel.tsx | 4 +- src/components/Map.tsx | 7 ++ src/components/Nav.tsx | 13 ++- src/components/PinkPulsePartner.tsx | 145 ++++++++++++++++++++++++++++ src/components/Providers.tsx | 6 +- src/components/SiteFooter.tsx | 96 ++++++++++++++++++ src/lib/partners.ts | 47 +++++++++ 15 files changed, 488 insertions(+), 10 deletions(-) create mode 100644 deploy/check-deploy-fail.py create mode 100644 deploy/check-deploy-fail2.py create mode 100644 deploy/redeploy-v2.py create mode 100644 public/partners/jtr-wordmark.svg create mode 100644 public/partners/pinkpulse-icon.svg create mode 100644 src/components/PinkPulsePartner.tsx create mode 100644 src/components/SiteFooter.tsx create mode 100644 src/lib/partners.ts diff --git a/deploy/check-deploy-fail.py b/deploy/check-deploy-fail.py new file mode 100644 index 0000000..db2791b --- /dev/null +++ b/deploy/check-deploy-fail.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python3 +import paramiko + +c = paramiko.SSHClient() +c.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +c.connect("10.10.0.10", username="localadministrator", password="Bbt9115xty9176!", timeout=20, allow_agent=False, look_for_keys=False) + +def run(cmd, t=120): + print("$", cmd[:200]) + _, o, e = c.exec_command(cmd, timeout=t) + code = o.channel.recv_exit_status() + out = (o.read() + e.read()).decode(errors="replace") + print(out[-12000:]) + print("exit", code, "\n") + return out + +run("cd /tmp/exposedgays && git fetch origin && git reset --hard origin/main && git log -1 --oneline") +run( + "docker exec coolify-db psql -U coolify -d coolify -t -c " + "\"SELECT id,status FROM application_deployment_queues ORDER BY id DESC LIMIT 5;\"" +) +run( + "docker exec coolify-db psql -U coolify -d coolify -t -c " + "\"SELECT deployment_logs FROM application_deployment_queues ORDER BY id DESC LIMIT 1;\" | tail -c 8000" +) +run("ls -la /data/coolify/applications/ira4bw4nhbvm87o7s3fgqu6v/logs/ 2>/dev/null | tail -5") +run("tail -80 /data/coolify/applications/ira4bw4nhbvm87o7s3fgqu6v/logs/*.log 2>/dev/null | tail -80") + +c.close() \ No newline at end of file diff --git a/deploy/check-deploy-fail2.py b/deploy/check-deploy-fail2.py new file mode 100644 index 0000000..ddc8c32 --- /dev/null +++ b/deploy/check-deploy-fail2.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +import paramiko + +c = paramiko.SSHClient() +c.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +c.connect("10.10.0.10", username="localadministrator", password="Bbt9115xty9176!", timeout=20, allow_agent=False, look_for_keys=False) + +def run(cmd, t=300): + print("$", cmd[:220]) + _, o, e = c.exec_command(cmd, timeout=t) + code = o.channel.recv_exit_status() + out = (o.read() + e.read()).decode(errors="replace") + print(out[-15000:]) + print("exit", code, "\n") + return out + +run("docker exec coolify-db psql -U coolify -d coolify -c \"\\d application_deployment_queues\"") +run("docker exec coolify-db psql -U coolify -d coolify -t -c \"SELECT logs FROM application_deployment_queues WHERE id=1116;\" | tail -c 12000") +run("find /data/coolify -name '*l9hjct9e8yxydqjl8okovpr5*' 2>/dev/null | head -5") +run("find /data/coolify -path '*ira4bw4nhbvm87o7s3fgqu6v*' -name '*.log' 2>/dev/null | head -10") +run("cd /data/coolify/applications/ira4bw4nhbvm87o7s3fgqu6v && docker compose build 2>&1 | tail -60") + +c.close() \ No newline at end of file diff --git a/deploy/redeploy-v2.py b/deploy/redeploy-v2.py new file mode 100644 index 0000000..6d4c1ab --- /dev/null +++ b/deploy/redeploy-v2.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +import paramiko + +HOST = "10.10.0.10" +USER = "localadministrator" +PASS = "Bbt9115xty9176!" +APP = "ira4bw4nhbvm87o7s3fgqu6v" + +c = paramiko.SSHClient() +c.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +c.connect(HOST, username=USER, password=PASS, timeout=20, allow_agent=False, look_for_keys=False) + +def run(cmd, t=300): + print("$", cmd[:180]) + _, o, e = c.exec_command(cmd, timeout=t) + code = o.channel.recv_exit_status() + out = (o.read() + e.read()).decode(errors="replace") + print(out[-6000:]) + print("exit", code, "\n") + return out + +run("cd /tmp/exposedgays && git fetch origin && git reset --hard origin/main && git log -1 --oneline") +run( + "TOKEN=$(cat /home/localadministrator/.coolify-token | tail -1); " + f"curl -sS -X POST 'http://127.0.0.1:8000/api/v1/deploy?uuid={APP}&force_rebuild=true' " + '-H "Authorization: Bearer $TOKEN"' +) + +for i in range(150): + _, out = run("docker exec coolify php artisan queue:work --queue=high,default --once --timeout=900 2>&1", t=920) + if "ApplicationDeploymentJob" in out: + if "DONE" in out or "finished" in out.lower(): + print("=== DEPLOY SUCCESS ===") + break + if "FAIL" in out: + print("=== DEPLOY FAILED ===") + break + +run("docker exec coolify-db psql -U coolify -d coolify -t -c \"SELECT id,status FROM application_deployment_queues ORDER BY id DESC LIMIT 1;\"") +run("curl -sS https://exposedgays.com/ 2>&1 | head -c 500") +c.close() \ No newline at end of file diff --git a/public/partners/jtr-wordmark.svg b/public/partners/jtr-wordmark.svg new file mode 100644 index 0000000..948bac9 --- /dev/null +++ b/public/partners/jtr-wordmark.svg @@ -0,0 +1,11 @@ + + + + Just Two Roommates — Wordmark + + JUST + TWO + ROOMMATES + + + diff --git a/public/partners/pinkpulse-icon.svg b/public/partners/pinkpulse-icon.svg new file mode 100644 index 0000000..03cf624 --- /dev/null +++ b/public/partners/pinkpulse-icon.svg @@ -0,0 +1,56 @@ + + + + + The Pink Pulse — Icon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/app/privacy/page.tsx b/src/app/privacy/page.tsx index 8d8f7c5..9494636 100644 --- a/src/app/privacy/page.tsx +++ b/src/app/privacy/page.tsx @@ -3,9 +3,11 @@ export default function PrivacyPage() {

Privacy Policy

- We collect minimal data. Location is used for map features and city chat auto-join. - Anonymous browsing is supported. Cart data stays in your browser (localStorage). - Placeholder policy — consult legal counsel before launch. + ExposedGays is operated by Just Two Roommates LLC. We collect minimal data. + Location is used for map features and city chat auto-join. Anonymous browsing + is supported. Cart data stays in your browser (localStorage). When you follow + links to our community partner The Pink Pulse, their privacy policy applies on + their site. Placeholder policy — consult legal counsel before launch.

); diff --git a/src/app/profile/page.tsx b/src/app/profile/page.tsx index 2c0fbdd..3c97f7c 100644 --- a/src/app/profile/page.tsx +++ b/src/app/profile/page.tsx @@ -15,6 +15,7 @@ import { AuthModal } from "@/components/AuthModal"; import { PhotoGalleryManager } from "@/components/PhotoGalleryManager"; import { CannedMessagesPanel } from "@/components/CannedMessagesPanel"; import { IdVerificationModal } from "@/components/IdVerificationModal"; +import { PinkPulsePartner } from "@/components/PinkPulsePartner"; import { US_STATES, getUserState, @@ -307,6 +308,8 @@ export default function ProfilePage() { + + {message && (

{message} diff --git a/src/app/terms/page.tsx b/src/app/terms/page.tsx index 7c3c673..fbce163 100644 --- a/src/app/terms/page.tsx +++ b/src/app/terms/page.tsx @@ -3,9 +3,12 @@ export default function TermsPage() {

Terms of Service

- ExposedGays is a free adult platform. You must be 18+ to use this site. - All content is user-generated. We reserve the right to remove illegal content. - No paid subscriptions — ever. Placeholder terms — consult legal counsel before launch. + ExposedGays is a free adult platform operated by Just Two Roommates LLC. You must + be 18+ to use this site. All content is user-generated. We reserve the right to + remove illegal content. No paid subscriptions — ever. Links to our community + partner The Pink Pulse (thepinkpulse.com) are provided for LGBTQ+ news, events, + and local resources — separate editorial property, same parent company. + Placeholder terms — consult legal counsel before launch.

); diff --git a/src/components/ChatPanel.tsx b/src/components/ChatPanel.tsx index b25e829..7ec0ecf 100644 --- a/src/components/ChatPanel.tsx +++ b/src/components/ChatPanel.tsx @@ -8,6 +8,7 @@ import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs"; import { Send, Image as ImageIcon, Users, Lock, Zap, ChevronDown, ChevronUp } from "lucide-react"; import { timeAgo } from "@/lib/utils"; import { CannedMessagesPanel } from "@/components/CannedMessagesPanel"; +import { PinkPulsePartner } from "@/components/PinkPulsePartner"; interface Message { id: string; @@ -148,9 +149,10 @@ export function ChatPanel({ dmUserId }: ChatPanelProps) { -

+

Create a group room — free, no limits.

+ diff --git a/src/components/Map.tsx b/src/components/Map.tsx index 2f0a44b..7c3d990 100644 --- a/src/components/Map.tsx +++ b/src/components/Map.tsx @@ -14,6 +14,7 @@ import type { Profile, CruisingSpot, MapFilters, Position } from "@/types"; import { KINK_OPTIONS, POSITION_COLORS } from "@/types"; import { MOCK_PROFILES, MOCK_SPOTS } from "@/lib/mock-data"; import { useOpenIdVerification } from "@/components/Providers"; +import { PinkPulsePartner } from "@/components/PinkPulsePartner"; import "leaflet/dist/leaflet.css"; import "leaflet.markercluster/dist/MarkerCluster.css"; @@ -279,9 +280,15 @@ export function CruisingMap({ vanillaMode, onActiveCountChange }: MapProps) { vanillaMode={vanillaMode} /> ))} + )} + {/* Mobile — community partner strip above bottom nav */} +
+ +
+ {/* Map */} {leafletReady && iconFactory && (
+ + + {PINK_PULSE.shortName} + {idBlur && onIdVerifyClick && (
+ ); + } + + if (variant === "inline") { + return ( + + + + Community partner: {PINK_PULSE.name} + + + + ); + } + + return ( +
+
+ + {PINK_PULSE.name} + +
+
+ +

+ Community partner +

+
+ + {PINK_PULSE.name} + +

{PINK_PULSE.tagline}

+
+
+ +
+ {PINK_PULSE.links.map((link) => ( + +

{link.label}

+

{link.description}

+ + ))} +
+ + + Visit thepinkpulse.com + + +
+ ); +} \ No newline at end of file diff --git a/src/components/Providers.tsx b/src/components/Providers.tsx index 8d63bd5..61a8093 100644 --- a/src/components/Providers.tsx +++ b/src/components/Providers.tsx @@ -5,6 +5,7 @@ import { AgeGate } from "@/components/AgeGate"; import { Nav } from "@/components/Nav"; import { MobileHeader } from "@/components/MobileHeader"; import { IdVerificationModal } from "@/components/IdVerificationModal"; +import { SiteFooter } from "@/components/SiteFooter"; import { AuthProvider, useAuth } from "@/lib/auth/context"; import { mustBlurExplicit, @@ -90,9 +91,10 @@ function InnerProviders({ children }: ProvidersProps) { onVanillaToggle={handleVanillaToggle} activeCount={activeCount} /> -
+
- {children} +
{children}
+
+
+
+ +
+ +
+
+

+ Designed & operated by +

+ + {JTR.name} + +

+ ExposedGays is a free adult platform from the Just Two Roommates media + family — alongside{" "} + + {PINK_PULSE.name} + + , your queer city guide. +

+
+ +
+ + Terms + + + Privacy + + + + {PINK_PULSE.shortName} + + + {JTR.name} + +
+
+ +

+ © {new Date().getFullYear()} Just Two Roommates LLC · ExposedGays.com · Free forever +

+
+ + ); +} \ No newline at end of file diff --git a/src/lib/partners.ts b/src/lib/partners.ts new file mode 100644 index 0000000..e7e8d04 --- /dev/null +++ b/src/lib/partners.ts @@ -0,0 +1,47 @@ +/** Just Two Roommates network — partner properties (JTR only, not RMP). */ + +export const JTR = { + name: "Just Two Roommates", + url: "https://justtworoommates.com", + logo: "/partners/jtr-wordmark.svg", +} as const; + +export const PINK_PULSE = { + name: "The Pink Pulse", + shortName: "Pink Pulse", + tagline: "LGBTQ+ news, events & 165+ cities", + url: "https://thepinkpulse.com", + logo: "/partners/pinkpulse-icon.svg", + links: [ + { + label: "The Latest", + href: "https://thepinkpulse.com/the-latest", + description: "Queer news & stories", + }, + { + label: "Events", + href: "https://thepinkpulse.com/events-calendar", + description: "This weekend near you", + }, + { + label: "Directory", + href: "https://thepinkpulse.com/directory", + description: "Local LGBTQ+ businesses", + }, + { + label: "Health", + href: "https://thepinkpulse.com/health-wellness", + description: "Testing, PrEP & wellness", + }, + { + label: "Nightlife", + href: "https://thepinkpulse.com/nightlife", + description: "Bars, drag & going out", + }, + { + label: "Groups", + href: "https://thepinkpulse.com/groups", + description: "Community meetups", + }, + ], +} as const; \ No newline at end of file