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
2 changes: 1 addition & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Ignorar dependencias locales
# node_modules se utilizará para mandarse desde github actions
node_modules

# Ignorar config de Git
.git
Expand Down
14 changes: 11 additions & 3 deletions .github/workflows/develop-CD.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ jobs:
mkdir -p ~/.ssh
ssh-keyscan ${{ secrets.GCP_VM_IP }} >> ~/.ssh/known_hosts

- name: Actualizar o agregar imagen en .env
uses: appleboy/ssh-action@v0.1.4
with:
host: ${{ secrets.GCP_VM_IP }}
username: ${{ secrets.GCP_VM_USER }}
key: ${{ secrets.GCP_SSH_KEY }}
script: |
cd /home/proyectosdanils/
sed -i '/^DOCKER_IMAGE_FRONTEND_DEV=/d' .env
echo "DOCKER_IMAGE_FRONTEND_DEV=${{ secrets.DOCKER_USERNAME }}/frontend-dev:${{ github.sha }}" >> .env

# 👉 Desplegar en la VM
- name: Deploy on GCP VM
uses: appleboy/ssh-action@v0.1.4
Expand All @@ -45,7 +56,4 @@ jobs:
script: |
cd /home/proyectosdanils/
docker compose down frontend-dev
docker pull ${{ secrets.DOCKER_USERNAME }}/frontend-dev:stage-${{ github.sha }}
export DOCKER_IMAGE_FRONTEND_PROD=placeholder
export DOCKER_IMAGE_FRONTEND_DEV=${{ secrets.DOCKER_USERNAME }}/frontend-dev:stage-${{ github.sha }}
docker compose up -d frontend-dev
14 changes: 11 additions & 3 deletions .github/workflows/master-CD.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,17 @@ jobs:
mkdir -p ~/.ssh
ssh-keyscan ${{ secrets.GCP_VM_IP }} >> ~/.ssh/known_hosts

- name: Actualizar o agregar imagen en .env
uses: appleboy/ssh-action@v0.1.4
with:
host: ${{ secrets.GCP_VM_IP }}
username: ${{ secrets.GCP_VM_USER }}
key: ${{ secrets.GCP_SSH_KEY }}
script: |
cd /home/proyectosdanils/
sed -i '/^DOCKER_IMAGE_FRONTEND_PROD=/d' .env
echo "DOCKER_IMAGE_FRONTEND_PROD=${{ secrets.DOCKER_USERNAME }}/frontend-prod:${{ github.sha }}" >> .env

# 👉 Desplegar en la VM
- name: Deploy on GCP VM
uses: appleboy/ssh-action@v0.1.4
Expand All @@ -46,7 +57,4 @@ jobs:
script: |
cd /home/proyectosdanils/
docker compose down frontend-prod
docker pull ${{ secrets.DOCKER_USERNAME }}/frontend-prod:${{ github.sha }}
export DOCKER_IMAGE_FRONTEND_DEV=placeholder
export DOCKER_IMAGE_FRONTEND_PROD=${{ secrets.DOCKER_USERNAME }}/frontend-prod:${{ github.sha }}
docker compose up -d frontend-prod
File renamed without changes.
36 changes: 29 additions & 7 deletions app/(auth)/login/_components/DesktopForm.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
export default function DesktopForm({ setMode }: { setMode: (mode: string) => void }) {
'use client';
import { useFormStatus } from 'react-dom';
interface Props {
setMode: (mode: string) => void;
registerAction: (e: React.FormEvent<HTMLFormElement>) => void;
loginAction: (e: React.FormEvent<HTMLFormElement>) => void;
}

export default function DesktopForm({ setMode, registerAction, loginAction }: Props) {
return (
<div className="hidden lg:flex gap-10 justify-between w-full">
<section className="w-[100%] flex flex-col items-center gap-5 max-w-[600px] mx-auto">
Expand All @@ -8,7 +16,7 @@ export default function DesktopForm({ setMode }: { setMode: (mode: string) => vo
</h1>
<h2>Inicia sesión para acceder a tus salas</h2>
</header>
<form className="flex flex-col gap-5 w-[80%]">
<form className="flex flex-col gap-5 w-[80%]" onSubmit={loginAction}>
<div className="flex flex-col gap-1">
<label htmlFor="email-login-desktop" className="font-bold">
Tu correo
Expand All @@ -19,6 +27,7 @@ export default function DesktopForm({ setMode }: { setMode: (mode: string) => vo
placeholder="Correo electrónico"
autoComplete="email"
className="w-full border-1 border-purple-300 p-2 rounded"
name="email"
/>
</div>
<div>
Expand All @@ -31,9 +40,10 @@ export default function DesktopForm({ setMode }: { setMode: (mode: string) => vo
placeholder="Contraseña"
className="w-full border-1 border-purple-300 p-2 rounded"
autoComplete="current-password"
name="password"
/>
</div>
<button className="bg-purple rounded p-2">Ingresar a la plataforma</button>
<SubmitButton text="Ingresar a la plataforma" />
</form>
<div className="flex gap-1">
<p>¿Aún no tienes una cuenta?</p>
Expand All @@ -48,16 +58,17 @@ export default function DesktopForm({ setMode }: { setMode: (mode: string) => vo
<h1 className="text-2xl font-extrabold text-center">Regístrate y Conecta</h1>
<h2>Podrás guardar tus conversaciones y salas</h2>
</header>
<form className="flex flex-col gap-5 w-[80%]">
<form className="flex flex-col gap-5 w-[80%]" onSubmit={registerAction}>
<div className="flex flex-col gap-1">
<label htmlFor="user-register-desktop" className="font-bold">
Tu ususuario
Tu usuario
</label>
<input
id="user-register-desktop"
type="text"
placeholder="Correo electrónico"
placeholder="Usuario"
className="w-full border-1 border-purple-300 p-2 rounded"
name="displayName"
/>
</div>
<div className="flex flex-col gap-1">
Expand All @@ -70,6 +81,7 @@ export default function DesktopForm({ setMode }: { setMode: (mode: string) => vo
placeholder="Correo electrónico"
autoComplete="email"
className="w-full border-1 border-purple-300 p-2 rounded"
name="email"
/>
</div>
<div>
Expand All @@ -82,9 +94,10 @@ export default function DesktopForm({ setMode }: { setMode: (mode: string) => vo
placeholder="Contraseña"
className="w-full border-1 border-purple-300 p-2 rounded"
autoComplete="current-password"
name="password"
/>
</div>
<button className="bg-purple rounded p-2">Crear cuenta</button>
<SubmitButton text="Crear cuenta" />
</form>
<div className="flex gap-1">
<p>¿Ya tienes una cuenta?</p>
Expand All @@ -96,3 +109,12 @@ export default function DesktopForm({ setMode }: { setMode: (mode: string) => vo
</div>
);
}

function SubmitButton({ text }: { text: string }) {
const { pending } = useFormStatus();
return (
<button disabled={pending} className="bg-purple rounded p-2">
{pending ? 'Cargando...' : text}
</button>
);
}
21 changes: 16 additions & 5 deletions app/(auth)/login/_components/MobileForm.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
'use client';
import { useState } from 'react';

interface Props {
mobileModeLogin: boolean;
setMobileModeLogin: (value: boolean) => void;
registerAction: (e: React.FormEvent<HTMLFormElement>) => void;
loginAction: (e: React.FormEvent<HTMLFormElement>) => void;
}
export default function MobileForm({ mobileModeLogin, setMobileModeLogin }: Props) {

export default function MobileForm({ registerAction, loginAction }: Props) {
const [mobileModeLogin, setMobileModeLogin] = useState(true);

return (
<div className="flex lg:hidden gap-10 justify-between w-full">
<section
Expand All @@ -14,7 +20,7 @@ export default function MobileForm({ mobileModeLogin, setMobileModeLogin }: Prop
</h1>
<h2>Inicia sesión para acceder a tus salas</h2>
</header>
<form className="flex flex-col gap-5 w-[80%]">
<form className="flex flex-col gap-5 w-[80%]" onSubmit={loginAction}>
<div className="flex flex-col gap-1">
<label htmlFor="email-login-mobile" className="font-bold">
Tu correo
Expand All @@ -25,6 +31,7 @@ export default function MobileForm({ mobileModeLogin, setMobileModeLogin }: Prop
placeholder="Correo electrónico"
autoComplete="email"
className="w-full border-1 border-purple-300 p-2 rounded"
name="email"
/>
</div>
<div>
Expand All @@ -37,6 +44,7 @@ export default function MobileForm({ mobileModeLogin, setMobileModeLogin }: Prop
placeholder="Contraseña"
autoComplete="current-password"
className="w-full border-1 border-purple-300 p-2 rounded"
name="password"
/>
</div>
<button className="bg-purple rounded p-2">Ingresar a la plataforma</button>
Expand All @@ -56,7 +64,7 @@ export default function MobileForm({ mobileModeLogin, setMobileModeLogin }: Prop
<h1 className="text-2xl font-extrabold text-center">Regístrate y Conecta</h1>
<h2>Podrás guardar tus conversaciones y salas</h2>
</header>
<form className="flex flex-col gap-5 w-[80%]">
<form className="flex flex-col gap-5 w-[80%]" onSubmit={registerAction}>
<div className="flex flex-col gap-1">
<label htmlFor="user-register-mobile" className="font-bold">
Tu ususuario
Expand All @@ -66,6 +74,7 @@ export default function MobileForm({ mobileModeLogin, setMobileModeLogin }: Prop
type="text"
placeholder="Correo electrónico"
className="w-full border-1 border-purple-300 p-2 rounded"
name="displayName"
/>
</div>
<div className="flex flex-col gap-1">
Expand All @@ -78,6 +87,7 @@ export default function MobileForm({ mobileModeLogin, setMobileModeLogin }: Prop
placeholder="Correo electrónico"
autoComplete="email"
className="w-full border-1 border-purple-300 p-2 rounded"
name="email"
/>
</div>
<div>
Expand All @@ -90,6 +100,7 @@ export default function MobileForm({ mobileModeLogin, setMobileModeLogin }: Prop
placeholder="Contraseña"
autoComplete="current-password"
className="w-full border-1 border-purple-300 p-2 rounded"
name="password"
/>
</div>
<button className="bg-purple rounded p-2">Crear cuenta</button>
Expand Down
19 changes: 19 additions & 0 deletions app/(auth)/login/_lib/_actions/session.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// app/actions/session.ts
'use server';

import { cookies } from 'next/headers';

export async function createSession(token: string) {
(await cookies()).set('session', token, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 60 * 60 * 24 * 7, // 1 semana
});
console.log('Session created with token:', token);
}

export async function deleteSession() {
(await cookies()).delete('session');
console.log('Session deleted');
}
15 changes: 15 additions & 0 deletions app/(auth)/login/_lib/_schemas/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { z } from 'zod';

export const registerSchema = z.object({
email: z.string().email({ message: 'Invalid email address' }).trim(),
password: z.string().min(6, { message: 'Password must be at least 6 characters long' }).trim(),
displayName: z
.string()
.min(3, { message: 'Display name must be at least 3 characters long' })
.trim(),
});

export const loginSchema = z.object({
email: z.string().email({ message: 'Invalid email address' }).trim(),
password: z.string().min(6, { message: 'Password must be at least 6 characters long' }).trim(),
});
23 changes: 20 additions & 3 deletions app/(auth)/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,27 @@ import Image from 'next/image';
import { useState } from 'react';
import DesktopForm from './_components/DesktopForm';
import MobileForm from './_components/MobileForm';
import { useRouter } from 'next/navigation';
import { useAuth } from '@/app/_hooks/useAuth';

export default function Login() {
const [mode, setMode] = useState('login');
const [mobileModeLogin, setMobileModeLogin] = useState(true);
const { login, register } = useAuth();
const router = useRouter();

const handleLogin = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
await login(formData);
router.push('/dashboard');
};

const handleRegister = async (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
await register(formData);
router.push('/dashboard');
};

return (
<section className="flex items-center min-h-screen w-full">
Expand All @@ -19,10 +36,10 @@ export default function Login() {
/>
<div className="w-full">
{/* Desktop */}
<DesktopForm setMode={setMode} />
<DesktopForm setMode={setMode} registerAction={handleRegister} loginAction={handleLogin} />

{/* Mobile */}
<MobileForm mobileModeLogin={mobileModeLogin} setMobileModeLogin={setMobileModeLogin} />
<MobileForm registerAction={handleRegister} loginAction={handleLogin} />
</div>
<Image
src="/squares/multicolor_dark.png"
Expand Down
2 changes: 1 addition & 1 deletion app/(protected)/dashboard/room/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import MessagesList from '../_components/MessagesList';
import { IMessage } from '@/app/_interfaces/IMessage';
import { IMessage } from '@/app/_lib/_interfaces/IMessage';

interface RouterProps {
params: Promise<{
Expand Down
2 changes: 1 addition & 1 deletion app/(protected)/dashboard/room/_components/Message.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IMessage } from '@/app/_interfaces/IMessage';
import { IMessage } from '@/app/_lib/_interfaces/IMessage';

interface Props {
message: IMessage;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';

import { useChatSocket } from '@/app/_hooks/useChatSocket';
import { IMessage } from '@/app/_interfaces/IMessage';
import { IMessage } from '@/app/_lib/_interfaces/IMessage';
import { useEffect, useRef, useState } from 'react';
import Message from './Message';
import useIsBottom from '@/app/_hooks/useScroll';
Expand Down
7 changes: 7 additions & 0 deletions app/_apis/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
'use server';
import { RegisterUserData } from '../_lib/_interfaces/IAuth';
import myAxios from './myAxios.config';

export const registerUser = async (data: RegisterUserData) => myAxios.post('/auth/signup', data);

export const verifySession = async () => myAxios.get('/api/v1/auth/me');
27 changes: 27 additions & 0 deletions app/_apis/myAxios.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import axios from 'axios';
import { getAuth } from 'firebase/auth';

const myAxios = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL,
headers: {
'Content-Type': 'application/json',
},
});

myAxios.interceptors.request.use(
async config => {
const user = getAuth().currentUser;
if (user) {
const token = await user.getIdToken();
config.headers.Authorization = `Bearer ${token}`;
}
console.log(process.env.NEXT_PUBLIC_API_URL, 'URL API');
return config;
},
error => {
console.error('Request error:', error);
return Promise.reject(error);
}
);

export default myAxios;
28 changes: 28 additions & 0 deletions app/_apis/mySSAxios.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import axios from 'axios';

const mySSAxios = axios.create({
baseURL: process.env.API_URL_SS,
headers: {
'Content-Type': 'application/json',
},
});

mySSAxios.interceptors.request.use(
// config => {
// const token = localStorage.getItem('token');
// if (token) {
// config.headers['Authorization'] = `Bearer ${token}`;
// }
// return config;
// },
config => {
console.log(process.env.API_URL_SS);
return config;
},
error => {
console.error('Request error:', error);
return Promise.reject(error);
}
);

export default mySSAxios;
Loading
Loading