mirror of
https://github.com/emailerfacu-spec/minix-front.git
synced 2026-04-23 16:34:28 -03:00
Merge pull request #1 from emailerfacu-spec/dev
Login, Register y Logout Terminado
This commit is contained in:
@@ -1,32 +1,44 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Button } from '$lib/components/ui/button/index.js';
|
import { Button } from '$lib/components/ui/button/index.js';
|
||||||
import * as Card from '$lib/components/ui/card/index.js';
|
import * as Card from '../components/ui/card';
|
||||||
import * as Field from '$lib/components/ui/field/index.js';
|
import * as Field from '$lib/components/ui/field';
|
||||||
import { Input } from '$lib/components/ui/input/index.js';
|
import { Input } from '$lib/components/ui/input/index.js';
|
||||||
import type { ComponentProps } from 'svelte';
|
import type { RegisterDto } from '../../types';
|
||||||
|
import { register } from '@/hooks/register';
|
||||||
|
|
||||||
|
let {showAlert = $bindable() } = $props();
|
||||||
|
|
||||||
|
const setAlert = () => showAlert = true;
|
||||||
|
|
||||||
|
let dto: RegisterDto = $state({password: "", username: "", email:"", displayName: ""});
|
||||||
|
|
||||||
let { ...restProps }: ComponentProps<typeof Card.Root> = $props();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Card.Root {...restProps}>
|
<Card.Root>
|
||||||
<Card.Header>
|
<Card.Header>
|
||||||
<Card.Title>Registrarse</Card.Title>
|
<Card.Title>Registrarse</Card.Title>
|
||||||
<hr />
|
<hr />
|
||||||
</Card.Header>
|
</Card.Header>
|
||||||
<Card.Content>
|
<Card.Content>
|
||||||
<form>
|
<form onsubmit={(e)=>register(e, dto, setAlert)}>
|
||||||
<Field.Group>
|
<Field.Group>
|
||||||
<Field.Field>
|
<Field.Field>
|
||||||
<Field.Label for="name">Nombre Completo</Field.Label>
|
<Field.Label for="name">Nombre de Usuario</Field.Label>
|
||||||
<Input id="name" type="text" placeholder="Juan Pepe" required />
|
<Input id="name" bind:value={dto.username} type="text" placeholder="JPepe" required />
|
||||||
</Field.Field>
|
</Field.Field>
|
||||||
|
|
||||||
|
<Field.Field>
|
||||||
|
<Field.Label for="name">Nombre Visible</Field.Label>
|
||||||
|
<Input type="text" bind:value={dto.displayName} placeholder="Juan Pepe" required />
|
||||||
|
</Field.Field>
|
||||||
|
|
||||||
<Field.Field>
|
<Field.Field>
|
||||||
<Field.Label for="email">Email</Field.Label>
|
<Field.Label for="email">Email</Field.Label>
|
||||||
<Input id="email" type="email" placeholder="m@ejemplo.com" required />
|
<Input id="email" type="email" bind:value={dto.email} placeholder="m@ejemplo.com" required />
|
||||||
</Field.Field>
|
</Field.Field>
|
||||||
<Field.Field>
|
<Field.Field>
|
||||||
<Field.Label for="password">Contraseña</Field.Label>
|
<Field.Label for="password">Contraseña</Field.Label>
|
||||||
<Input id="password" type="password" required />
|
<Input id="password" type="password" bind:value={dto.password} required />
|
||||||
<Field.Description>Debe de tener por lo menos 8 caracteres.</Field.Description>
|
<Field.Description>Debe de tener por lo menos 8 caracteres.</Field.Description>
|
||||||
</Field.Field>
|
</Field.Field>
|
||||||
<Field.Field>
|
<Field.Field>
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
import { cn, type WithElementRef } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
children,
|
||||||
|
...restProps
|
||||||
|
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
bind:this={ref}
|
||||||
|
data-slot="alert-description"
|
||||||
|
class={cn(
|
||||||
|
"text-muted-foreground col-start-2 grid justify-items-start gap-1 text-sm [&_p]:leading-relaxed",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
{@render children?.()}
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
import { cn, type WithElementRef } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
children,
|
||||||
|
...restProps
|
||||||
|
}: WithElementRef<HTMLAttributes<HTMLDivElement>> = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
bind:this={ref}
|
||||||
|
data-slot="alert-title"
|
||||||
|
class={cn("col-start-2 line-clamp-1 min-h-4 font-medium tracking-tight", className)}
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
{@render children?.()}
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<script lang="ts" module>
|
||||||
|
import { type VariantProps, tv } from "tailwind-variants";
|
||||||
|
|
||||||
|
export const alertVariants = tv({
|
||||||
|
base: "relative grid w-full grid-cols-[0_1fr] items-start gap-y-0.5 rounded-lg border px-4 py-3 text-sm has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current",
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: "bg-card text-card-foreground",
|
||||||
|
destructive:
|
||||||
|
"text-destructive bg-card *:data-[slot=alert-description]:text-destructive/90 [&>svg]:text-current",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: "default",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export type AlertVariant = VariantProps<typeof alertVariants>["variant"];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
import { cn, type WithElementRef } from "$lib/utils.js";
|
||||||
|
|
||||||
|
let {
|
||||||
|
ref = $bindable(null),
|
||||||
|
class: className,
|
||||||
|
variant = "default",
|
||||||
|
children,
|
||||||
|
...restProps
|
||||||
|
}: WithElementRef<HTMLAttributes<HTMLDivElement>> & {
|
||||||
|
variant?: AlertVariant;
|
||||||
|
} = $props();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div
|
||||||
|
bind:this={ref}
|
||||||
|
data-slot="alert"
|
||||||
|
class={cn(alertVariants({ variant }), className)}
|
||||||
|
{...restProps}
|
||||||
|
role="alert"
|
||||||
|
>
|
||||||
|
{@render children?.()}
|
||||||
|
</div>
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import Root from "./alert.svelte";
|
||||||
|
import Description from "./alert-description.svelte";
|
||||||
|
import Title from "./alert-title.svelte";
|
||||||
|
export { alertVariants, type AlertVariant } from "./alert.svelte";
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
Description,
|
||||||
|
Title,
|
||||||
|
//
|
||||||
|
Root as Alert,
|
||||||
|
Description as AlertDescription,
|
||||||
|
Title as AlertTitle,
|
||||||
|
};
|
||||||
@@ -3,7 +3,13 @@
|
|||||||
import * as Card from '@/components/ui/card';
|
import * as Card from '@/components/ui/card';
|
||||||
import { Input } from '@/components/ui/input';
|
import { Input } from '@/components/ui/input';
|
||||||
import { FieldGroup, Field, FieldLabel, FieldDescription } from '@/components/ui/field';
|
import { FieldGroup, Field, FieldLabel, FieldDescription } from '@/components/ui/field';
|
||||||
const id = $props.id();
|
import type { LoginDto } from '../../../../types';
|
||||||
|
import { login } from '@/hooks/login';
|
||||||
|
let {id, showAlert = $bindable() } = $props();
|
||||||
|
|
||||||
|
let dto: LoginDto = $state({password: "", username: ""});
|
||||||
|
|
||||||
|
const setAlert = () => showAlert = true;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Card.Root class="mx-auto w-full max-w-sm">
|
<Card.Root class="mx-auto w-full max-w-sm">
|
||||||
@@ -12,11 +18,11 @@
|
|||||||
<Card.Description>ingrese su usuario para logearse en la cuenta</Card.Description>
|
<Card.Description>ingrese su usuario para logearse en la cuenta</Card.Description>
|
||||||
</Card.Header>
|
</Card.Header>
|
||||||
<Card.Content>
|
<Card.Content>
|
||||||
<form>
|
<form onsubmit="{(e)=>login(e,dto, setAlert)}">
|
||||||
<FieldGroup>
|
<FieldGroup>
|
||||||
<Field>
|
<Field>
|
||||||
<FieldLabel for="email-{id}">Usuario</FieldLabel>
|
<FieldLabel for="email-{id}">Usuario</FieldLabel>
|
||||||
<Input id="email-{id}" type="email" placeholder="m@example.com" required />
|
<Input bind:value={dto.username} type="text" placeholder="nombre de usuario" required />
|
||||||
</Field>
|
</Field>
|
||||||
<Field>
|
<Field>
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
@@ -25,7 +31,7 @@
|
|||||||
Te Olvidaste la contraseña?
|
Te Olvidaste la contraseña?
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<Input id="password-{id}" type="password" required />
|
<Input bind:value={dto.password} type="password" required />
|
||||||
</Field>
|
</Field>
|
||||||
<Field>
|
<Field>
|
||||||
<Button type="submit" class="w-full">Login</Button>
|
<Button type="submit" class="w-full">Login</Button>
|
||||||
|
|||||||
+73
-27
@@ -4,9 +4,45 @@
|
|||||||
import ButtonGroup from '@/components/ui/button-group/button-group.svelte';
|
import ButtonGroup from '@/components/ui/button-group/button-group.svelte';
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/state';
|
||||||
import { slide } from 'svelte/transition';
|
import { slide } from 'svelte/transition';
|
||||||
|
import { sesionStore } from '@/stores/usuario';
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import { apiBase } from '@/stores/url';
|
||||||
|
|
||||||
let menuOpen = $state(false);
|
let menuOpen = $state(false);
|
||||||
const toggleMenu = () => (menuOpen = !menuOpen);
|
const toggleMenu = () => (menuOpen = !menuOpen);
|
||||||
|
|
||||||
|
let showCerrarSesion = $state(false);
|
||||||
|
|
||||||
|
onMount(()=>{
|
||||||
|
sesionStore.subscribe((value)=>{
|
||||||
|
showCerrarSesion = !!value?.accessToken;
|
||||||
|
})
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
async function cerrarSesion(){
|
||||||
|
try{
|
||||||
|
const req = await fetch($apiBase+"/api/auth/logout", {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": `Bearer ${$sesionStore?.accessToken}`
|
||||||
|
|
||||||
|
},
|
||||||
|
credentials: "include"
|
||||||
|
});
|
||||||
|
if(req.ok){
|
||||||
|
|
||||||
|
sesionStore.reset();
|
||||||
|
menuOpen = false;
|
||||||
|
}
|
||||||
|
}catch{
|
||||||
|
console.log("fallo el lougout")
|
||||||
|
} finally{
|
||||||
|
sesionStore.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<header class="border-b bg-background/95 backdrop-blur">
|
<header class="border-b bg-background/95 backdrop-blur">
|
||||||
@@ -22,19 +58,24 @@
|
|||||||
|
|
||||||
<!-- Desktop menu -->
|
<!-- Desktop menu -->
|
||||||
<div class="hidden flex-1 items-center justify-end md:flex">
|
<div class="hidden flex-1 items-center justify-end md:flex">
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
<Button
|
{#if showCerrarSesion}
|
||||||
variant={page.url.pathname !== '/login' ? 'outline' : 'secondary'}
|
<Button onclick={cerrarSesion}> Cerrar Sesion
|
||||||
href="/login"
|
</Button>
|
||||||
class="text-foreground/60 transition-colors hover:text-foreground/80"
|
{:else}
|
||||||
>Iniciar Sesion</Button
|
<Button
|
||||||
>
|
variant={page.url.pathname !== '/login' ? 'outline' : 'secondary'}
|
||||||
<Button
|
href="/login"
|
||||||
variant={page.url.pathname !== '/register' ? 'outline' : 'secondary'}
|
class="text-foreground/60 transition-colors hover:text-foreground/80"
|
||||||
href="/register"
|
>Iniciar Sesion
|
||||||
class="text-foreground/60 transition-colors hover:text-foreground/80">Registrarse</Button
|
</Button>
|
||||||
>
|
<Button
|
||||||
</ButtonGroup>
|
variant={page.url.pathname !== '/register' ? 'outline' : 'secondary'}
|
||||||
|
href="/register"
|
||||||
|
class="text-foreground/60 transition-colors hover:text-foreground/80">Registrarse
|
||||||
|
</Button>
|
||||||
|
{/if}
|
||||||
|
</ButtonGroup>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Mobile menu button -->
|
<!-- Mobile menu button -->
|
||||||
@@ -64,20 +105,25 @@
|
|||||||
<!-- Mobile menu -->
|
<!-- Mobile menu -->
|
||||||
{#if menuOpen}
|
{#if menuOpen}
|
||||||
<div class="md:hidden" transition:slide>
|
<div class="md:hidden" transition:slide>
|
||||||
<div class="space-y-1 border-t bg-background/95 px-2 pt-2 pb-3">
|
<div class="space-y-1 border-t bg-background/95 px-2 pt-2 pb-3">
|
||||||
<Button
|
{#if showCerrarSesion}
|
||||||
variant={page.url.pathname !== '/login' ? 'outline' : 'secondary'}
|
<Button onclick={cerrarSesion}> Cerrar Sesion
|
||||||
href="/login"
|
</Button>
|
||||||
class="mb-2 w-full justify-start text-foreground/60 transition-colors hover:text-foreground/80"
|
{:else}
|
||||||
onclick={() => (menuOpen = false)}>Iniciar Sesion</Button
|
<Button
|
||||||
>
|
variant={page.url.pathname !== '/login' ? 'outline' : 'secondary'}
|
||||||
<Button
|
href="/login"
|
||||||
variant={page.url.pathname !== '/register' ? 'outline' : 'secondary'}
|
class="mb-2 w-full justify-start text-foreground/60 transition-colors hover:text-foreground/80"
|
||||||
href="/register"
|
onclick={() => (menuOpen = false)}>Iniciar Sesion</Button
|
||||||
class="w-full justify-start text-foreground/60 transition-colors hover:text-foreground/80"
|
>
|
||||||
onclick={() => (menuOpen = false)}>Registrarse</Button
|
<Button
|
||||||
>
|
variant={page.url.pathname !== '/register' ? 'outline' : 'secondary'}
|
||||||
</div>
|
href="/register"
|
||||||
|
class="w-full justify-start text-foreground/60 transition-colors hover:text-foreground/80"
|
||||||
|
onclick={() => (menuOpen = false)}>Registrarse
|
||||||
|
</Button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</header>
|
</header>
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import { apiBase } from "@/stores/url";
|
||||||
|
import type { LoginDto } from "../../types";
|
||||||
|
import { sesionStore } from "@/stores/usuario";
|
||||||
|
import { goto } from "$app/navigation";
|
||||||
|
|
||||||
|
export async function login(e:FormDataEvent,dto: LoginDto, callbackfn:()=>void){
|
||||||
|
e.preventDefault();
|
||||||
|
if (dto.password == "" || dto.username == "") return;
|
||||||
|
try {
|
||||||
|
|
||||||
|
const { subscribe } = apiBase;
|
||||||
|
let baseUrl: string = '';
|
||||||
|
|
||||||
|
subscribe((value) => {
|
||||||
|
baseUrl = value;
|
||||||
|
})();
|
||||||
|
const req = await fetch(baseUrl + "/api/auth/login", {
|
||||||
|
method: "POST",
|
||||||
|
headers:{
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
credentials: 'include',
|
||||||
|
body: JSON.stringify(dto)
|
||||||
|
});
|
||||||
|
if (req.ok) {
|
||||||
|
const token = await req.json();
|
||||||
|
sesionStore.set(token);
|
||||||
|
goto("/")
|
||||||
|
} else {
|
||||||
|
callbackfn();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
callbackfn();
|
||||||
|
console.error("fallo al intentar alcanzar el servidor")
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { apiBase } from "@/stores/url";
|
||||||
|
import { goto } from "$app/navigation";
|
||||||
|
import type { RegisterDto } from "../../types";
|
||||||
|
|
||||||
|
export async function register(e:FormDataEvent,dto: RegisterDto, callbackfn:()=>void){
|
||||||
|
e.preventDefault();
|
||||||
|
if (dto.password == "" || dto.username == "" ||
|
||||||
|
!dto.email?.includes("@") || dto.displayName=="") return;
|
||||||
|
try {
|
||||||
|
|
||||||
|
const { subscribe } = apiBase;
|
||||||
|
let baseUrl: string = '';
|
||||||
|
|
||||||
|
subscribe((value) => {
|
||||||
|
baseUrl = value;
|
||||||
|
})();
|
||||||
|
const req = await fetch(baseUrl + "/api/auth/register", {
|
||||||
|
method: "POST",
|
||||||
|
headers:{
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
},
|
||||||
|
body: JSON.stringify(dto)
|
||||||
|
});
|
||||||
|
if (req.ok) {
|
||||||
|
const data= await req.json();
|
||||||
|
goto("/login?msg="+data.message);
|
||||||
|
} else {
|
||||||
|
callbackfn();
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
callbackfn();
|
||||||
|
console.error("fallo al intentar alcanzar el servidor")
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { writable } from 'svelte/store';
|
||||||
|
import type { Sesion } from '../../types';
|
||||||
|
|
||||||
|
export const currentSesion = writable<Sesion| null>(null);
|
||||||
|
|
||||||
|
export const sesionStore = {
|
||||||
|
subscribe: currentSesion.subscribe,
|
||||||
|
set: currentSesion.set,
|
||||||
|
update: currentSesion.update,
|
||||||
|
reset: () => currentSesion.set(null)
|
||||||
|
};
|
||||||
+21
-4
@@ -2,12 +2,29 @@
|
|||||||
import Card from '@/components/ui/card/card.svelte';
|
import Card from '@/components/ui/card/card.svelte';
|
||||||
import type { Post } from '../types';
|
import type { Post } from '../types';
|
||||||
import { Content } from '@/components/ui/card';
|
import { Content } from '@/components/ui/card';
|
||||||
|
import { apiBase } from '@/stores/url';
|
||||||
|
|
||||||
interface Props {
|
$effect(()=>{
|
||||||
posts: Post[];
|
getPosts();
|
||||||
}
|
});
|
||||||
|
|
||||||
|
let posts: Post[] = $state([]);
|
||||||
|
|
||||||
|
async function getPosts() {
|
||||||
|
const { subscribe } = apiBase;
|
||||||
|
let baseUrl: string = '';
|
||||||
|
|
||||||
|
subscribe((value) => {
|
||||||
|
baseUrl = value;
|
||||||
|
})();
|
||||||
|
|
||||||
|
const req = await fetch(`${baseUrl}/api/posts/timeline?pageSize=3`);
|
||||||
|
if (req.ok){
|
||||||
|
posts = await req.json();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
let { posts = [] }: Props = $props();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex min-h-fit w-full items-center justify-center p-6 md:p-10">
|
<div class="flex min-h-fit w-full items-center justify-center p-6 md:p-10">
|
||||||
|
|||||||
@@ -1,16 +1 @@
|
|||||||
import { apiBase } from '@/stores/url';
|
|
||||||
|
|
||||||
export const ssr = true;
|
export const ssr = true;
|
||||||
|
|
||||||
export async function load({}) {
|
|
||||||
const { subscribe } = apiBase;
|
|
||||||
let baseUrl: string = '';
|
|
||||||
|
|
||||||
subscribe((value) => {
|
|
||||||
baseUrl = value;
|
|
||||||
})();
|
|
||||||
|
|
||||||
const req = await fetch(`${baseUrl}/Posts`);
|
|
||||||
if (req.ok) return { posts: req };
|
|
||||||
else return { posts: [] };
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export function load({ url }) {
|
||||||
|
return {
|
||||||
|
message: url.searchParams.get('msg')
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,9 +1,60 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import LoginForm from '@/components/ui/login-form/login-form.svelte';
|
import * as Alert from '@/components/ui/alert';
|
||||||
</script>
|
import LoginForm from '@/components/ui/login-form/login-form.svelte';
|
||||||
|
import AlertCircleIcon from "@lucide/svelte/icons/alert-circle";
|
||||||
|
import { fade, fly } from 'svelte/transition';
|
||||||
|
import Info from '@lucide/svelte/icons/info';
|
||||||
|
|
||||||
|
let {data} = $props();
|
||||||
|
|
||||||
|
let showAlert: boolean = $state(false);
|
||||||
|
|
||||||
|
let message = $state(data.message);
|
||||||
|
|
||||||
|
$effect(()=>{
|
||||||
|
resetAlert();
|
||||||
|
if (data.message) {
|
||||||
|
history.replaceState(history.state, "", "/login");
|
||||||
|
setTimeout(() => {
|
||||||
|
message = "";
|
||||||
|
}, 7000);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function resetAlert (){
|
||||||
|
if (showAlert == true){
|
||||||
|
await new Promise(res => setTimeout(res, 2000));
|
||||||
|
showAlert=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<div class="flex min-h-fit w-full items-center justify-center p-6 md:p-10">
|
<div class="flex min-h-fit w-full items-center justify-center p-6 md:p-10">
|
||||||
<LoginForm />
|
<div class="w-full max-w-sm">
|
||||||
|
{#if message}
|
||||||
|
<div class="mb-2" transition:fly>
|
||||||
|
<Alert.Root>
|
||||||
|
<Info />
|
||||||
|
<Alert.Title>Info</Alert.Title>
|
||||||
|
<Alert.Description>
|
||||||
|
Ingrese las credenciales de la cuenta recien creada
|
||||||
|
</Alert.Description>
|
||||||
|
</Alert.Root>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/if}
|
||||||
|
<LoginForm bind:showAlert={showAlert} id="1" />
|
||||||
|
{#if showAlert}
|
||||||
|
<div class="mt-2" transition:fade>
|
||||||
|
<Alert.Root variant="destructive">
|
||||||
|
<AlertCircleIcon />
|
||||||
|
<Alert.Title>No se pudo iniciar sesion</Alert.Title>
|
||||||
|
<Alert.Description>
|
||||||
|
Revise su usuario o contraseña
|
||||||
|
</Alert.Description>
|
||||||
|
</Alert.Root>
|
||||||
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,38 @@
|
|||||||
<script>
|
<script lang="ts">
|
||||||
import SignupForm from '@/components/signup-form.svelte';
|
import SignupForm from '@/components/signup-form.svelte';
|
||||||
|
|
||||||
|
import AlertCircleIcon from "@lucide/svelte/icons/alert-circle";
|
||||||
|
import * as Alert from '@/components/ui/alert';
|
||||||
|
import { fade } from 'svelte/transition';
|
||||||
|
|
||||||
|
let showAlert: boolean = $state(false);
|
||||||
|
|
||||||
|
$effect(()=>{
|
||||||
|
resetAlert();
|
||||||
|
});
|
||||||
|
|
||||||
|
async function resetAlert (){
|
||||||
|
if (showAlert == true){
|
||||||
|
await new Promise(res => setTimeout(res, 2000));
|
||||||
|
showAlert=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex min-h-fit w-full items-center justify-center p-6 md:p-10">
|
<div class="flex min-h-fit w-full items-center justify-center p-6 md:p-10">
|
||||||
<div class="w-full max-w-sm">
|
<div class="w-full max-w-sm">
|
||||||
<SignupForm />
|
<SignupForm bind:showAlert={showAlert} />
|
||||||
|
{#if showAlert}
|
||||||
|
<div class="mt-2" transition:fade>
|
||||||
|
<Alert.Root variant="destructive">
|
||||||
|
<AlertCircleIcon />
|
||||||
|
<Alert.Title>No se pudo crear la cuenta</Alert.Title>
|
||||||
|
<Alert.Description>
|
||||||
|
Intente nuevamente.
|
||||||
|
</Alert.Description>
|
||||||
|
</Alert.Root>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Vendored
+32
@@ -12,3 +12,35 @@ export interface Post {
|
|||||||
visibility: string;
|
visibility: string;
|
||||||
hashtags?: string[];
|
hashtags?: string[];
|
||||||
}
|
}
|
||||||
|
export interface User {
|
||||||
|
_id: string;
|
||||||
|
displayName: string;
|
||||||
|
username: string;
|
||||||
|
email: string;
|
||||||
|
passwordHash: string;
|
||||||
|
bio?: string;
|
||||||
|
profileImageUrl?: string;
|
||||||
|
createdAt: Date;
|
||||||
|
followersCount: number;
|
||||||
|
followingCount: number;
|
||||||
|
refreshTokens: RefreshToken[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Sesion {
|
||||||
|
accessToken:string?;
|
||||||
|
message:string;
|
||||||
|
url:string;
|
||||||
|
displayname:string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LoginDto {
|
||||||
|
username: string?;
|
||||||
|
password: string?;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RegisterDto {
|
||||||
|
username: string?;
|
||||||
|
email: string?;
|
||||||
|
password: string?;
|
||||||
|
displayName: string?;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user