Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
## ?? Cambios
- [ Actualizar y mejorar] Frontend
- [ Actualizar y mejorar] Backend

## ? Checklist
- [ ] El PR compila localmente (`frontend` y `backend`)
- [ ] Pasan linters/tests (si aplica)
- [ ] No subo archivos pesados o secretos

## ?? C�mo probar
1. `cd frontend && npm ci && npm run build`
2. `cd ../backend && ./gradlew build`

Aprender autonomo PR
96 changes: 96 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
name: CI

on:
pull_request:
branches: [ "main" ]

jobs:
frontend:
name: Frontend (demo)
runs-on: ubuntu-latest
defaults:
run:
working-directory: demo
steps:
- uses: actions/checkout@v4

- name: Detectar tipo de proyecto
id: detect
run: |
if [ -f "package.json" ]; then echo "node_project=true" >> $GITHUB_OUTPUT; fi
if [ -f "index.html" ]; then echo "static_html=true" >> $GITHUB_OUTPUT; fi
echo "Node? $([[ -f package.json ]] && echo YES || echo NO)"
echo "HTML? $([[ -f index.html ]] && echo YES || echo NO)"

# Solo si es proyecto Node (Next/React/etc.)
- name: Setup Node
if: ${{ steps.detect.outputs.node_project == 'true' }}
uses: actions/setup-node@v4
with:
node-version: 18
cache: npm
cache-dependency-path: demo/package-lock.json

- name: Instalar dependencias (Node)
if: ${{ steps.detect.outputs.node_project == 'true' }}
run: |
if [ -f package-lock.json ]; then npm ci; else npm install; fi

- name: Build (Node)
if: ${{ steps.detect.outputs.node_project == 'true' }}
env:
NEXT_TELEMETRY_DISABLED: 1
CI: false
run: npm run build --if-present

# Si NO es proyecto Node y SOLO hay HTML estático, valida que exista el archivo y pasa
- name: Validar HTML estático
if: ${{ steps.detect.outputs.node_project != 'true' && steps.detect.outputs.static_html == 'true' }}
run: |
test -f index.html
echo "OK: proyecto estático con index.html"

backend:
name: Backend
runs-on: ubuntu-latest
defaults:
run:
working-directory: backend
steps:
- uses: actions/checkout@v4

- name: Detectar herramienta de build
id: b
run: |
if [ -f "gradlew" ] || [ -f "build.gradle" ] || [ -f "build.gradle.kts" ]; then echo "use_gradle=true" >> $GITHUB_OUTPUT; fi
if [ -f "pom.xml" ]; then echo "use_maven=true" >> $GITHUB_OUTPUT; fi
echo "Gradle? $([[ -f gradlew || -f build.gradle || -f build.gradle.kts ]] && echo YES || echo NO)"
echo "Maven? $([[ -f pom.xml ]] && echo YES || echo NO)"

- name: Setup Java
if: ${{ steps.b.outputs.use_gradle == 'true' || steps.b.outputs.use_maven == 'true' }}
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17 # súbelo a 21 si tu build.gradle/pom lo exige

- uses: gradle/actions/setup-gradle@v3
if: ${{ steps.b.outputs.use_gradle == 'true' }}

- name: Permisos para gradlew
if: ${{ steps.b.outputs.use_gradle == 'true' && hashFiles('backend/gradlew') != '' }}
run: chmod +x gradlew

- name: Build (Gradle)
if: ${{ steps.b.outputs.use_gradle == 'true' }}
run: |
if [ -f gradlew ]; then ./gradlew build --no-daemon --stacktrace; \
else gradle build --no-daemon --stacktrace; fi

- name: Build (Maven)
if: ${{ steps.b.outputs.use_maven == 'true' }}
run: mvn -B -DskipTests package

- name: No hay proyecto backend detectable (OK)
if: ${{ steps.b.outputs.use_gradle != 'true' && steps.b.outputs.use_maven != 'true' }}
run: echo "Sin build.gradle/pom.xml en backend: se omite build y el job pasa."
23 changes: 23 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Frontend
frontend/node_modules/
frontend/.next/
frontend/.turbo/
frontend/dist/
frontend/out/
frontend/.vercel/

# Backend
backend/.gradle/
backend/build/
backend/out/
backend/logs/

# General
*.log
.env

# Node/Next (por tu frontend)
node_modules/
.next/
dist/
out/
Binary file modified backend/.gradle/8.9/executionHistory/executionHistory.bin
Binary file not shown.
Binary file modified backend/.gradle/8.9/executionHistory/executionHistory.lock
Binary file not shown.
Binary file modified backend/.gradle/8.9/fileHashes/fileHashes.bin
Binary file not shown.
Binary file modified backend/.gradle/8.9/fileHashes/fileHashes.lock
Binary file not shown.
Binary file modified backend/.gradle/8.9/fileHashes/resourceHashesCache.bin
Binary file not shown.
Binary file modified backend/.gradle/9.0.0/checksums/checksums.lock
Binary file not shown.
Binary file modified backend/.gradle/9.0.0/checksums/md5-checksums.bin
Binary file not shown.
Binary file modified backend/.gradle/9.0.0/checksums/sha1-checksums.bin
Binary file not shown.
Binary file modified backend/.gradle/9.0.0/executionHistory/executionHistory.bin
Binary file not shown.
Binary file modified backend/.gradle/9.0.0/executionHistory/executionHistory.lock
Binary file not shown.
Binary file modified backend/.gradle/9.0.0/fileHashes/fileHashes.bin
Binary file not shown.
Binary file modified backend/.gradle/9.0.0/fileHashes/fileHashes.lock
Binary file not shown.
Binary file modified backend/.gradle/buildOutputCleanup/buildOutputCleanup.lock
Binary file not shown.
2 changes: 1 addition & 1 deletion backend/.gradle/buildOutputCleanup/cache.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
#Fri Aug 15 19:34:19 GMT-05:00 2025
#Sat Aug 23 19:16:40 GMT-05:00 2025
gradle.version=8.9
Binary file modified backend/.gradle/buildOutputCleanup/outputFiles.bin
Binary file not shown.
Binary file modified backend/.gradle/file-system.probe
Binary file not shown.
Binary file not shown.
Binary file removed backend/build/libs/sismoview-backend-0.1.0.jar
Binary file not shown.
10 changes: 0 additions & 10 deletions backend/build/tmp/bootJar/MANIFEST.MF
Original file line number Diff line number Diff line change
@@ -1,12 +1,2 @@
Manifest-Version: 1.0
Main-Class: org.springframework.boot.loader.launch.JarLauncher
Start-Class: com.sismoview.SismoViewBackendApplication
Spring-Boot-Version: 3.3.2
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Spring-Boot-Classpath-Index: BOOT-INF/classpath.idx
Spring-Boot-Layers-Index: BOOT-INF/layers.idx
Build-Jdk-Spec: 21
Implementation-Title: sismoview-backend
Implementation-Version: 0.1.0

Binary file modified backend/build/tmp/compileJava/previous-compilation-data.bin
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//importaciones necesarias para el proyecto
package com.sismoview.adapters.bathy;

import com.sismoview.domain.ports.BathymetryPort;
Expand Down
1 change: 1 addition & 0 deletions frontend/.env.local
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
NEXT_PUBLIC_API_BASE=http://localhost:8080
3 changes: 3 additions & 0 deletions frontend/app/assets/textures
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
earth_political_4k.jpg
earth_normal_2k.jpg
earth_normal_2k.jpg
184 changes: 167 additions & 17 deletions frontend/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,173 @@
'use client';
import React, { useState } from 'react';
import { GlobeScene } from '../components/GlobeScene';
import { SimulationControls } from '../components/SimulationControls';

export default function Page(){
const [ev,setEv] = useState<{lat:number, lon:number, mag:number}|null>(null);
const [running,setRunning] = useState(false);
const [start,setStart] = useState<number|undefined>(undefined);

function onStart(lat:number, lon:number, mag:number){
setEv({lat,lon,mag}); setStart(performance.now()); setRunning(true);
"use client";

import { useState, useMemo } from "react";
import dynamic from "next/dynamic";

const Globe = dynamic(() => import("../components/Globe"), { ssr: false });
const Stats = dynamic(() => import("../components/Stats"), { ssr: false });

const API_BASE = process.env.NEXT_PUBLIC_API_BASE ?? "http://localhost:8080";

type SimResponse = {
rings?: { P: { minutes: number; radiusKm: number }[]; S: { minutes: number; radiusKm: number }[] };
arrivals?: { place: string; type: "P" | "S"; minutes: number }[];
intensity?: { gridId: string; legend: { label: string; colorHex: string }[] };
};

export default function Home() {
const [lat, setLat] = useState("10.5");
const [lon, setLon] = useState("166.3");
const [mag, setMag] = useState("6.3");
const [loading, setLoading] = useState(false);
const [resp, setResp] = useState<SimResponse | null>(null);
const [error, setError] = useState<string | null>(null);

const center = useMemo(() => {
const la = Number(lat);
const lo = Number(lon);
if (Number.isFinite(la) && Number.isFinite(lo)) return { lat: la, lon: lo };
return null;
}, [lat, lon]);

async function simular() {
setLoading(true);
setError(null);

const la = Number(lat);
const lo = Number(lon);
const m = Number(mag);

if (!Number.isFinite(la) || !Number.isFinite(lo) || !Number.isFinite(m)) {
setLoading(false);
setError("Lat/Lon/M deben ser números válidos.");
return;
}

try {
const r = await fetch(`${API_BASE}/api/simulate/seismic`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
lat: la,
lon: lo,
depthKm: 10,
magnitude: m,
cities: [
{ name: "Bogotá", lat: 4.711, lon: -74.0721 },
{ name: "Tokio", lat: 35.6762, lon: 139.6503 },
],
}),
});

if (!r.ok) {
const txt = await r.text().catch(() => "");
throw new Error(`HTTP ${r.status} ${txt}`);
}
const data: SimResponse = await r.json();
setResp(data);
console.log("Simulación OK:", data);
} catch (e: any) {
console.error("Error al simular:", e);
setError(e?.message ?? "Error inesperado");
setResp(null);
} finally {
setLoading(false);
}
}

return (
<main className="p-4 max-w-6xl mx-auto">
<h1 className="text-2xl font-semibold mb-3">SismoView – MVP</h1>
<SimulationControls onStart={onStart} />
<div className="mt-4">
<GlobeScene epicenter={ev?{lat:ev.lat,lon:ev.lon}:undefined} simStart={start} running={running} />
<main className="min-h-screen bg-slate-900 text-slate-100">
<header className="sticky top-0 z-50 bg-slate-900/90 backdrop-blur border-b border-slate-800">
<div className="max-w-6xl mx-auto p-4 flex flex-wrap gap-3 items-end">
<h1 className="text-xl font-semibold mr-auto">SismoView – MVP</h1>

<label className="text-sm">
Lat
<input
className="mt-1 block bg-slate-800 px-3 py-2 rounded w-28"
value={lat}
onChange={(e) => setLat(e.target.value)}
inputMode="decimal"
/>
</label>

<label className="text-sm">
Lon
<input
className="mt-1 block bg-slate-800 px-3 py-2 rounded w-28"
value={lon}
onChange={(e) => setLon(e.target.value)}
inputMode="decimal"
/>
</label>

<label className="text-sm">
M
<input
className="mt-1 block bg-slate-800 px-3 py-2 rounded w-24"
value={mag}
onChange={(e) => setMag(e.target.value)}
inputMode="decimal"
/>
</label>

<button
type="button"
onClick={simular}
disabled={loading}
className="bg-teal-500 hover:bg-teal-400 disabled:opacity-60 text-black font-semibold px-4 py-2 rounded"
>
{loading ? "Simulando..." : "Simular"}
</button>
</div>
</header>

<div className="max-w-6xl mx-auto p-4 grid grid-cols-1 lg:grid-cols-3 gap-4">
<section className="lg:col-span-2">
<div className="relative h-[60vh] rounded-xl border border-slate-800 overflow-hidden bg-black">
{/* Importante: evita que el Canvas tape los controles */}
{/* El Canvas está solo dentro de este contenedor, bajo el header */}
{center && (
<Globe
center={center}
rings={resp?.rings ?? null}
intensity={resp?.intensity ?? null}
/>
)}
</div>

{error && (
<p className="mt-3 text-red-400 break-words">Error: {error}</p>
)}
</section>

<aside className="lg:col-span-1">
<div className="rounded-xl border border-slate-800 p-3 bg-slate-950/50">
<Stats
center={center ?? { lat: 0, lon: 0 }}
rings={resp?.rings ?? null}
arrivals={resp?.arrivals ?? []}
intensity={resp?.intensity ?? null}
/>
</div>

{!resp && !error && (
<p className="text-slate-400 text-sm mt-3">
Pulsa “Simular” para ver anillos P/S e intensidad.
</p>
)}
</aside>

{resp && (
<details className="lg:col-span-3 rounded-xl border border-slate-800 p-3 bg-slate-950/30">
<summary className="cursor-pointer text-slate-300">
Ver JSON dev (debug)
</summary>
<pre className="mt-2 text-xs overflow-auto max-h-72">
{JSON.stringify(resp, null, 2)}
</pre>
</details>
)}
</div>
</main>
);
Expand Down
Loading