update
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
@import "tailwindcss";
|
||||
@import 'tailwindcss';
|
||||
|
||||
@theme {
|
||||
--font-sans: "Roboto", ui-sans-serif, system-ui, sans-serif,
|
||||
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||
--font-sans:
|
||||
'Roboto', ui-sans-serif, system-ui, sans-serif, 'Apple Color Emoji',
|
||||
'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
||||
|
||||
--color-yellow-primary: #ffcf82;
|
||||
--color-yellow-secondary: #f2ebe1;
|
||||
@@ -14,6 +15,7 @@
|
||||
--color-green-support: #c9fcad;
|
||||
--color-green-pastel: #f9fff6;
|
||||
--color-green-light: #cad9b4;
|
||||
--color-green-dark: #4e8630;
|
||||
}
|
||||
|
||||
html,
|
||||
|
||||
5
dashboard_js/app/axios.js
Normal file
5
dashboard_js/app/axios.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import axios from 'axios'
|
||||
|
||||
export default axios.create({
|
||||
baseURL: import.meta.env.VITE_API_URL,
|
||||
})
|
||||
@@ -84,5 +84,5 @@ export function MenuItems({ children, className, ...props }) {
|
||||
}
|
||||
|
||||
export function MenuSeparator() {
|
||||
return <hr className="my-2 dark:border-t-slate-600" />
|
||||
return <hr className="my-2 border-gray-200 dark:border-t-slate-600" />
|
||||
}
|
||||
|
||||
@@ -24,9 +24,13 @@ export function AuthProvider({ children }) {
|
||||
const [authUser, setAuthUser] = useState(null)
|
||||
|
||||
useEffect(() => {
|
||||
Auth.fetchUserAttributes().then((user) => {
|
||||
setAuthUser(user)
|
||||
})
|
||||
Auth.fetchUserAttributes()
|
||||
.then((user) => {
|
||||
setAuthUser(user)
|
||||
})
|
||||
.catch(() => {
|
||||
setAuthUser(null)
|
||||
})
|
||||
}, [])
|
||||
|
||||
const signIn = useCallback(async ({ username, password }) => {
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import { useNavigation, redirect, useNavigate } from 'react-router'
|
||||
import { fetchAuthSession } from 'aws-amplify/auth'
|
||||
import { Link } from 'react-router'
|
||||
import {
|
||||
AcademicCapIcon,
|
||||
PresentationChartLineIcon,
|
||||
UserGroupIcon,
|
||||
ShoppingBagIcon,
|
||||
Bars3BottomLeftIcon,
|
||||
} from '@heroicons/react/24/outline'
|
||||
import { NavLink } from 'react-router'
|
||||
import { Outlet } from 'react-router'
|
||||
import { Container } from '~/components/container'
|
||||
import { Smallest, Regular } from '~/components/logo'
|
||||
@@ -21,24 +28,41 @@ export default function Layout() {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<aside className="p-4 w-80 h-full fixed top-0 left-0 dark:bg-green-primary max-lg:hidden">
|
||||
<Logo className="h-12 lg:h-14" />
|
||||
<aside
|
||||
role="navigation"
|
||||
className="p-4 w-80 h-full fixed top-0 left-0 bg-yellow-terciary dark:bg-green-primary z-40 overflow-y-auto max-lg:hidden"
|
||||
>
|
||||
<div className="space-y-6">
|
||||
<Logo className="h-12 lg:h-14" />
|
||||
|
||||
<ul className="flex flex-col gap-1">
|
||||
<li>
|
||||
<Link to="/orders">Pagamentos</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/users">Usuários</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to="/enrollments">Matrículas</Link>
|
||||
</li>
|
||||
</ul>
|
||||
<ul className="space-y-1 font-medium">
|
||||
<Link to="/" icon={PresentationChartLineIcon}>
|
||||
<>Visão geral</>
|
||||
</Link>
|
||||
|
||||
<Link to="/orders" icon={ShoppingBagIcon}>
|
||||
<>Pagamentos</>
|
||||
</Link>
|
||||
|
||||
<Link to="/users" icon={UserGroupIcon}>
|
||||
<>Usuários</>
|
||||
</Link>
|
||||
|
||||
<Link to="/enrollments" icon={AcademicCapIcon}>
|
||||
Matriculas
|
||||
</Link>
|
||||
</ul>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
<section className="lg:ml-80">
|
||||
<header className="flex items-center bg-slate-50/50 dark:bg-gray-900/50 backdrop-blur backdrop-filter sticky top-0 border-b dark:border-gray-700 lg:border-0 z-20 h-16 px-4 lg:px-8">
|
||||
<header className="flex items-center bg-slate-50/50 dark:bg-gray-900/50 backdrop-blur backdrop-filter sticky top-0 border-b border-gray-200 dark:border-gray-700 lg:border-0 z-20 h-16 px-4 lg:px-8">
|
||||
{/* Mobile menu button */}
|
||||
<button className="lg:hidden" onClick={() => setIsOpen(true)}>
|
||||
<span className="sr-only">Abrir barra lateral</span>
|
||||
<Bars3BottomLeftIcon className="w-6" />
|
||||
</button>
|
||||
|
||||
<div className="ml-auto flex items-center">
|
||||
<UserMenu />
|
||||
</div>
|
||||
@@ -52,6 +76,20 @@ export default function Layout() {
|
||||
)
|
||||
}
|
||||
|
||||
function Link({ children, icon: Icon, ...props }) {
|
||||
return (
|
||||
<li>
|
||||
<NavLink
|
||||
className="aria-[current=page]:text-white aria-[current=page]:bg-green-dark hover:bg-green-secondary dark:hover:text-white p-2.5 rounded-lg flex gap-2 transition"
|
||||
{...props}
|
||||
>
|
||||
<Icon className="w-6" />
|
||||
<span>{children}</span>
|
||||
</NavLink>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
function Loading() {
|
||||
return (
|
||||
<Container>
|
||||
@@ -74,8 +112,8 @@ function Loading() {
|
||||
function Logo({ className }) {
|
||||
return (
|
||||
<div>
|
||||
<Regular className={clsx('max-lg:hidden', className)} />
|
||||
<Smallest className={clsx('lg:hidden w-full', className)} />
|
||||
<Regular className={clsx(className)} />
|
||||
{/* <Smallest className={clsx('lg:hidden w-full', className)} /> */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
13
dashboard_js/app/routes/auth/_base64state.js
Normal file
13
dashboard_js/app/routes/auth/_base64state.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import { encodeURI, decode } from 'js-base64'
|
||||
|
||||
export function encode(data) {
|
||||
return encodeURI(JSON.stringify(data))
|
||||
}
|
||||
|
||||
export function parse(str) {
|
||||
try {
|
||||
return JSON.parse(decode(str))
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ import { Heading } from '~/components/heading'
|
||||
import { Link } from '~/layouts/auth/_link'
|
||||
import { Card } from '~/layouts/auth/layout'
|
||||
import * as yup from 'yup'
|
||||
import { parse } from '../_base64state'
|
||||
|
||||
const schema = yup.object({
|
||||
password: yup
|
||||
@@ -33,6 +34,7 @@ export default function Password() {
|
||||
const { register, formState, setError, handleSubmit } = useForm({
|
||||
resolver: yupResolver(schema),
|
||||
})
|
||||
const state = parse(searchParams.get('state'))
|
||||
|
||||
const formError = (message) => {
|
||||
setError('password', {
|
||||
@@ -42,7 +44,7 @@ export default function Password() {
|
||||
}
|
||||
|
||||
const onSubmit = async ({ password }) => {
|
||||
const username = searchParams.get('username')
|
||||
const username = state?.email
|
||||
const redirectTo = searchParams.get('redirect') ?? '/'
|
||||
|
||||
try {
|
||||
@@ -114,9 +116,7 @@ export default function Password() {
|
||||
|
||||
<p className="break-all">
|
||||
Entre na sua conta usando o email{' '}
|
||||
<span className="font-semibold">
|
||||
{searchParams.get('username')}
|
||||
</span>{' '}
|
||||
<span className="font-semibold">{state?.email}</span>{' '}
|
||||
<Link to="." as={RouterLink}>
|
||||
(editar)
|
||||
</Link>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useNavigate, useSearchParams, Link } from 'react-router'
|
||||
import { useSearchParams, Link } from 'react-router'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { ErrorMessage } from '@hookform/error-message'
|
||||
import { isValidCPF } from '@brazilian-utils/brazilian-utils'
|
||||
@@ -6,8 +6,11 @@ import { yupResolver } from '@hookform/resolvers/yup'
|
||||
import { Card } from '~/layouts/auth/layout'
|
||||
import { Control, Label, Input, Button, Error } from '~/components/form'
|
||||
import { Heading } from '~/components/heading'
|
||||
import Password from './_password'
|
||||
import { useMutation } from '@tanstack/react-query'
|
||||
import * as yup from 'yup'
|
||||
import { encode, parse } from '../_base64state'
|
||||
import axios from '~/axios'
|
||||
import Password from './_password'
|
||||
|
||||
yup.addMethod(yup.string, 'username', function (message) {
|
||||
return this.test(
|
||||
@@ -29,8 +32,9 @@ export const schema = yup.object({
|
||||
|
||||
export default function Component() {
|
||||
const [searchParams] = useSearchParams()
|
||||
const state = parse(searchParams.get('state'))
|
||||
|
||||
if (searchParams.get('username')) {
|
||||
if (state?.['cognito:sub']) {
|
||||
return <Password />
|
||||
}
|
||||
|
||||
@@ -43,9 +47,18 @@ function SignIn() {
|
||||
resolver: yupResolver(schema),
|
||||
})
|
||||
|
||||
const { mutateAsync } = useMutation({
|
||||
mutationFn: async ({ username }) => {
|
||||
const { data } = await axios.get(`/search/lookup/${username}`)
|
||||
return data
|
||||
},
|
||||
})
|
||||
|
||||
const onSubmit = async ({ username }) => {
|
||||
const data = await mutateAsync({ username })
|
||||
|
||||
setSearchParams((searchParams) => {
|
||||
searchParams.set('username', username)
|
||||
searchParams.set('state', encode(data))
|
||||
return searchParams
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user