Code Snippets - xStreamer
Login API
import {
Body, Controller, Post, UsePipes, ValidationPipe
} from '@nestjs/common';
import { DataResponse } from 'src/core';
import { LoginPasswordPayload } from 'src/payloads';
import { AuthService } from 'src/services';
@Controller('/auth/login')
export class LoginController {
constructor(
private authService: AuthService
) {}
@Post()
@UsePipes(new ValidationPipe({ transform: true, whitelist: true }))
async register(
@Body() payload: LoginPasswordPayload
) {
const res = await this.authService.loginWithPassword(payload);
return DataResponse.ok(res);
}
}
Login form
'use client';
import Link from 'next/link';
import { Formik, Form, Field, FieldProps } from 'formik';
import { signIn } from 'next-auth/react';
import { useTranslation } from 'react-i18next';
import * as yup from 'yup';
import { FormItem, Input } from '@components/ui/form';
import { useState } from 'react';
import { FormattedMessage } from '@components/i18n';
import { useMainThemeLayout } from 'src/providers/main-layout.provider';
const schema = yup.object().shape({
username: yup.string().required('Username is required!'),
password: yup.string().required('Password is required!')
});
export default function Login() {
const { t } = useTranslation();
const [error, setError] = useState<string | null>();
const { register, forgotPassword, closePopup } = useMainThemeLayout();
return (
<div className="w-full space-y-5 p-10 text-center">
<Link href="/" className="font-bold text-4xl text-center">
xStreamer
</Link>
<h2 className="text-center text-2xl font-bold leading-9 tracking-tigh">
{t('signin', 'Sign in')}
</h2>
<Formik
initialValues={{ username: '', password: '' }}
validationSchema={schema}
onSubmit={async (values, actions) => {
const res = await signIn('credentials', {
...values,
redirect: false
});
if (res && res.ok) {
closePopup();
// loadProfile();
return;
}
setError(res!.error);
actions.setSubmitting(false);
}}
>
{({ handleSubmit }) => (
<Form className="space-y-3" onSubmit={handleSubmit}>
<Field name="username">
{({ field, meta }: FieldProps) => (
<FormItem>
<Input placeholder="Username" {...field} />
{meta.touched && !!meta.error && (
<FormItem.Error>{meta.error}</FormItem.Error>
)}
</FormItem>
)}
</Field>
<div>
<Field name="password">
{({ field, meta }: FieldProps) => (
<FormItem>
<Input type="password" placeholder="Password" {...field} />
{meta.touched && !!meta.error && (
<FormItem.Error>{meta.error}</FormItem.Error>
)}
</FormItem>
)}
</Field>
</div>
<div className="flex items-center justify-between">
<div className="text-sm text-primary">
<button onClick={forgotPassword} role="button" type="button">
<FormattedMessage
id="forgotPassword"
defaultValue="Forgot password"
subifx="?"
/>
</button>
</div>
</div>
{error && (
<div
className="bg-red-100 dark:bg-red-950 border border-red-900 text-red-700 dark:text-white px-4 py-3 rounded relative"
role="alert"
>
<span className="text-sm font-medium">{error}</span>
</div>
)}
<div className="text-center">
<button
type="submit"
className="rounded-md bg-orange-600 px-3 py-1.5 text-sm font-semibold leading-6 text-white shadow-sm hover:bg-orange-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-orange-600"
>
{t('signin', 'Sign in')}
</button>
</div>
</Form>
)}
</Formik>
<p className="mt-10 text-center text-sm text-gray-500">
Don't have an account?
{' '}
<a
onClick={register}
className="font-semibold leading-6 cursor-pointer hover:text-primary"
>
{t('signup', 'Sign Up')}
</a>
</p>
</div>
);
}