1
0

Role based access, and lots of style changes, login/signup pages still look funky in dark mode

This commit is contained in:
Ahmed Al-Taiar
2023-10-31 23:25:39 -04:00
parent fcdacd844f
commit f5a6b1c37a
20 changed files with 172 additions and 235 deletions

View File

@ -21,7 +21,7 @@ const Routes = () => {
<Route path="/signup" page={SignupPage} name="signup" />
<Route path="/forgot-password" page={ForgotPasswordPage} name="forgotPassword" />
<Route path="/reset-password" page={ResetPasswordPage} name="resetPassword" />
<Private unauthenticated="home">
<Private unauthenticated="home" roles="admin">
<Set wrap={ScaffoldLayout} title="Parts" titleTo="parts" buttonLabel="New Part" buttonTo="newPart">
<Route path="/admin/parts/new" page={PartNewPartPage} name="newPart" />
<Route path="/admin/parts/{id:Int}/edit" page={PartEditPartPage} name="editPart" />

View File

@ -1,11 +1,11 @@
import type { CreatePartInput } from 'types/graphql'
import { navigate, routes } from '@redwoodjs/router'
import { useMutation } from '@redwoodjs/web'
import { toast } from '@redwoodjs/web/toast'
import PartForm from 'src/components/Part/PartForm'
import type { CreatePartInput } from 'types/graphql'
const CREATE_PART_MUTATION = gql`
mutation CreatePartMutation($input: CreatePartInput!) {
createPart(input: $input) {

View File

@ -75,13 +75,13 @@ const Part = ({ part }: Props) => {
<nav className="rw-button-group">
<Link
to={routes.editPart({ id: part.id })}
className="rw-button rw-button-blue"
className="rw-button btn-primary"
>
Edit
</Link>
<button
type="button"
className="rw-button rw-button-red"
className="rw-button btn-error"
onClick={() => onDeleteClick(part.id)}
>
Delete

View File

@ -11,6 +11,7 @@ import {
TextField,
NumberField,
Submit,
TextAreaField,
} from '@redwoodjs/forms'
import type { RWGqlError } from '@redwoodjs/forms'
@ -36,6 +37,7 @@ const PartForm = (props: PartFormProps) => {
}
const preview = (url: string) => {
if (url.includes('no_image.png')) return url
const parts = url.split('/')
parts.splice(3, 0, 'resize=height:500')
return parts.join('/')
@ -51,58 +53,37 @@ const PartForm = (props: PartFormProps) => {
listClassName="rw-form-error-list"
/>
<Label
name="name"
className="rw-label"
errorClassName="rw-label rw-label-error"
>
Name
</Label>
<TextField
name="name"
placeholder="Name"
defaultValue={props.part?.name}
className="rw-input"
errorClassName="rw-input rw-input-error"
className="rw-input mb-3 min-w-full"
errorClassName="rw-input rw-input-error min-w-full"
validation={{ required: true }}
/>
<FieldError name="name" className="rw-field-error" />
<FieldError name="name" className="rw-field-error pb-3" />
<Label
name="description"
className="rw-label"
errorClassName="rw-label rw-label-error"
>
Description
</Label>
<TextField
<TextAreaField
name="description"
placeholder="Description"
defaultValue={props.part?.description}
className="rw-input"
className="rw-textarea mb-1 min-w-full"
errorClassName="rw-input rw-input-error"
/>
<FieldError name="description" className="rw-field-error" />
<Label
name="availableStock"
className="rw-label"
errorClassName="rw-label rw-label-error"
>
Available stock
</Label>
<FieldError name="description" className="rw-field-error pb-3" />
<NumberField
name="availableStock"
defaultValue={props.part?.availableStock}
className="rw-input"
errorClassName="rw-input rw-input-error"
validation={{ required: true }}
defaultValue={props.part?.availableStock ?? 0}
className="rw-input min-w-full"
errorClassName="rw-input rw-input-error min-w-full"
validation={{ required: true, min: 0 }}
min={0}
/>
<FieldError name="availableStock" className="rw-field-error" />
<FieldError name="availableStock" className="rw-field-error pb-3" />
<Label
name="imageUrl"
@ -141,7 +122,7 @@ const PartForm = (props: PartFormProps) => {
<FieldError name="imageUrl" className="rw-field-error" />
<div className="rw-button-group">
<Submit disabled={props.loading} className="rw-button rw-button-blue">
<Submit disabled={props.loading} className="rw-button btn-primary">
Save
</Submit>
</div>

View File

@ -37,6 +37,7 @@ const PartsList = ({ parts }: FindParts) => {
}
const thumbnail = (url: string) => {
if (url.includes('no_image.png')) return url
const parts = url.split('/')
parts.splice(3, 0, 'resize=width:100')
return parts.join('/')
@ -85,14 +86,14 @@ const PartsList = ({ parts }: FindParts) => {
<Link
to={routes.editPart({ id: part.id })}
title={'Edit part ' + part.id}
className="rw-button rw-button-small rw-button-blue"
className="rw-button rw-button-small btn-primary"
>
Edit
</Link>
<button
type="button"
title={'Delete part ' + part.id}
className="rw-button rw-button-small rw-button-red"
className="rw-button rw-button-small btn-error"
onClick={() => onDeleteClick(part.id)}
>
Delete

View File

@ -22,8 +22,8 @@ export const Loading = () => <div>Loading...</div>
export const Empty = () => {
return (
<div className="rw-text-center">
{'No parts yet. '}
<div className="rw-text-center p-4">
<span className="font-inter">No parts yet.</span>{' '}
<Link to={routes.newPart()} className="rw-link">
{'Create one?'}
</Link>

View File

@ -20,12 +20,10 @@ const ScaffoldLayout = ({
<div className="rw-scaffold">
<Toaster toastOptions={{ className: 'rw-toast', duration: 6000 }} />
<header className="rw-header">
<h1 className="rw-heading rw-heading-primary">
<Link to={routes[titleTo]()} className="rw-link">
{title}
</Link>
<h1 className="rw-heading rw-heading-primary rw-button btn-ghost normal-case">
<Link to={routes[titleTo]()}>{title}</Link>
</h1>
<Link to={routes[buttonTo]()} className="rw-button rw-button-green">
<Link to={routes[buttonTo]()} className="rw-button btn-success">
<div className="rw-button-icon">+</div> {buttonLabel}
</Link>
</header>

View File

@ -1,6 +1,6 @@
import { useEffect, useRef } from 'react'
import { Form, Label, TextField, Submit, FieldError } from '@redwoodjs/forms'
import { Form, TextField, Submit, FieldError } from '@redwoodjs/forms'
import { navigate, routes } from '@redwoodjs/router'
import { MetaTags } from '@redwoodjs/web'
import { toast, Toaster } from '@redwoodjs/web/toast'
@ -46,42 +46,38 @@ const ForgotPasswordPage = () => {
<div className="rw-scaffold rw-login-container">
<div className="rw-segment">
<header className="rw-segment-header">
<h2 className="rw-heading rw-heading-secondary">
Forgot Password
</h2>
<h2 className="rw-heading rw-heading-primary">Forgot Password</h2>
</header>
<div className="rw-segment-main">
<div className="rw-form-wrapper">
<Form onSubmit={onSubmit} className="rw-form-wrapper">
<div className="text-left">
<Label
name="email"
className="rw-label"
errorClassName="rw-label rw-label-error"
>
Email
</Label>
<TextField
name="email"
className="rw-input"
errorClassName="rw-input rw-input-error"
placeholder="Email"
className="rw-input mb-3 min-w-full"
errorClassName="rw-input rw-input-error min-w-full"
ref={emailRef}
validation={{
required: {
value: true,
message: 'Email is required',
},
pattern: {
value: new RegExp(
/^([a-zA-Z0-9_\-\.]+)@([a-zA-Z0-9_\-]+)(\.[a-zA-Z]{2,5}){1,2}$/
),
message: 'Email is not valid',
},
}}
/>
<FieldError name="email" className="rw-field-error" />
<FieldError name="email" className="rw-field-error pb-3" />
</div>
<div className="rw-button-group">
<Submit className="btn btn-primary font-inter">
Submit
</Submit>
<Submit className="rw-button btn-primary">Submit</Submit>
</div>
</Form>
</div>

View File

@ -3,7 +3,6 @@ import { useEffect } from 'react'
import {
Form,
Label,
TextField,
PasswordField,
Submit,
@ -53,23 +52,17 @@ const LoginPage = () => {
<div className="rw-scaffold rw-login-container">
<div className="rw-segment">
<header className="rw-segment-header">
<h2 className="rw-heading rw-heading-secondary">Login</h2>
<h2 className="rw-heading rw-heading-primary">Login</h2>
</header>
<div className="rw-segment-main">
<div className="rw-form-wrapper">
<Form onSubmit={onSubmit} className="rw-form-wrapper">
<Label
name="email"
className="rw-label"
errorClassName="rw-label rw-label-error"
>
Email
</Label>
<TextField
name="email"
className="rw-input"
errorClassName="rw-input rw-input-error"
placeholder="Email"
className="rw-input mb-3 min-w-full"
errorClassName="rw-input rw-input-error min-w-full"
ref={emailRef}
validation={{
required: {
@ -79,19 +72,13 @@ const LoginPage = () => {
}}
/>
<FieldError name="email" className="rw-field-error" />
<FieldError name="email" className="rw-field-error pb-3" />
<Label
name="password"
className="rw-label"
errorClassName="rw-label rw-label-error"
>
Password
</Label>
<PasswordField
name="password"
className="rw-input"
errorClassName="rw-input rw-input-error"
placeholder="Password"
className="rw-input mb-3 min-w-full"
errorClassName="rw-input rw-input-error min-w-full"
autoComplete="current-password"
validation={{
required: {
@ -113,9 +100,7 @@ const LoginPage = () => {
</div>
<div className="rw-button-group">
<Submit className="btn btn-primary font-inter">
Login
</Submit>
<Submit className="rw-button btn-primary ">Login</Submit>
</div>
</Form>
</div>

View File

@ -1,12 +1,6 @@
import { useEffect, useRef, useState } from 'react'
import {
Form,
Label,
PasswordField,
Submit,
FieldError,
} from '@redwoodjs/forms'
import { Form, PasswordField, Submit, FieldError } from '@redwoodjs/forms'
import { navigate, routes } from '@redwoodjs/router'
import { MetaTags } from '@redwoodjs/web'
import { toast, Toaster } from '@redwoodjs/web/toast'
@ -66,27 +60,19 @@ const ResetPasswordPage = ({ resetToken }: { resetToken: string }) => {
<div className="rw-scaffold rw-login-container">
<div className="rw-segment">
<header className="rw-segment-header">
<h2 className="rw-heading rw-heading-secondary">
Reset Password
</h2>
<h2 className="rw-heading rw-heading-primary">Reset Password</h2>
</header>
<div className="rw-segment-main">
<div className="rw-form-wrapper">
<Form onSubmit={onSubmit} className="rw-form-wrapper">
<div className="text-left">
<Label
name="password"
className="rw-label"
errorClassName="rw-label rw-label-error"
>
New Password
</Label>
<PasswordField
name="password"
placeholder="New password"
autoComplete="new-password"
className="rw-input"
errorClassName="rw-input rw-input-error"
className="rw-input mb-3 min-w-full"
errorClassName="rw-input rw-input-error min-w-full"
disabled={!enabled}
ref={passwordRef}
validation={{
@ -97,12 +83,15 @@ const ResetPasswordPage = ({ resetToken }: { resetToken: string }) => {
}}
/>
<FieldError name="password" className="rw-field-error" />
<FieldError
name="password"
className="rw-field-error pb-3"
/>
</div>
<div className="rw-button-group">
<Submit
className="btn btn-primary font-inter"
className="rw-button btn-primary"
disabled={!enabled}
>
Submit

View File

@ -3,7 +3,6 @@ import { useEffect } from 'react'
import {
Form,
Label,
TextField,
PasswordField,
FieldError,
@ -31,7 +30,6 @@ const SignupPage = () => {
}, [])
const onSubmit = async (data: Record<string, string>) => {
console.log(data)
const response = await signUp({
username: data.email,
password: data.password,
@ -58,22 +56,16 @@ const SignupPage = () => {
<div className="rw-scaffold rw-login-container">
<div className="rw-segment">
<header className="rw-segment-header">
<h2 className="rw-heading rw-heading-secondary">Signup</h2>
<h2 className="rw-heading rw-heading-primary">Sign up</h2>
</header>
<div className="rw-segment-main">
<div className="rw-form-wrapper">
<Form onSubmit={onSubmit} className="rw-form-wrapper">
<div className="flex justify-between space-x-3">
<div className="mb-3 flex justify-between space-x-3">
<div>
<Label
name="firstName"
className="mt-6 block text-left font-semibold text-gray-600"
errorClassName="rw-label rw-label-error"
>
First Name
</Label>
<TextField
placeholder="First Name"
name="firstName"
className="rw-input"
errorClassName="rw-input rw-input-error"
@ -89,15 +81,9 @@ const SignupPage = () => {
</div>
<div>
<Label
name="lastName"
className="rw-label"
errorClassName="rw-label rw-label-error"
>
Last Name
</Label>
<TextField
name="lastName"
placeholder="Last Name"
className="rw-input"
errorClassName="rw-input rw-input-error"
validation={{
@ -111,17 +97,11 @@ const SignupPage = () => {
</div>
</div>
<Label
name="email"
className="rw-label"
errorClassName="rw-label rw-label-error"
>
Email
</Label>
<TextField
name="email"
className="rw-input"
errorClassName="rw-input rw-input-error"
placeholder="Email"
className="rw-input mb-3 min-w-full"
errorClassName="rw-input rw-input-error min-w-full"
validation={{
required: {
value: true,
@ -135,19 +115,13 @@ const SignupPage = () => {
},
}}
/>
<FieldError name="email" className="rw-field-error" />
<FieldError name="email" className="rw-field-error pb-3" />
<Label
name="password"
className="rw-label"
errorClassName="rw-label rw-label-error"
>
Password
</Label>
<PasswordField
name="password"
className="rw-input"
errorClassName="rw-input rw-input-error"
placeholder="Password"
className="rw-input min-w-full"
errorClassName="rw-input rw-input-error min-w-full"
autoComplete="current-password"
validation={{
required: {
@ -159,9 +133,7 @@ const SignupPage = () => {
<FieldError name="password" className="rw-field-error" />
<div className="rw-button-group">
<Submit className="btn btn-primary font-inter">
Sign Up
</Submit>
<Submit className="rw-button btn-primary">Sign Up</Submit>
</div>
</Form>
</div>

View File

@ -5,9 +5,6 @@
.rw-scaffold h2 {
@apply m-0;
}
.rw-scaffold a {
@apply bg-transparent;
}
.rw-scaffold ul {
@apply m-0 p-0;
}
@ -21,10 +18,10 @@
@apply text-gray-500;
}
.rw-header {
@apply flex justify-between px-8 py-4;
@apply navbar items-center justify-between space-x-3 bg-base-100 shadow-lg;
}
.rw-main {
@apply mx-4 pb-4;
@apply m-4;
}
.rw-segment {
@apply w-full overflow-hidden rounded-lg border border-gray-200;
@ -46,19 +43,19 @@
@apply bg-gray-100 p-4;
}
.rw-link {
@apply text-blue-400 underline font-inter;
@apply font-inter text-blue-400 underline;
}
.rw-link:hover {
@apply text-blue-500;
}
.rw-forgot-link {
@apply mt-1 text-right text-xs text-gray-400 underline font-inter;
@apply mt-1 text-right font-inter text-xs text-gray-400 underline;
}
.rw-forgot-link:hover {
@apply text-blue-500;
}
.rw-heading {
@apply font-semibold font-inter;
@apply font-inter font-semibold;
}
.rw-heading.rw-heading-primary {
@apply text-xl;
@ -76,7 +73,7 @@
@apply text-sm font-semibold;
}
.rw-form-wrapper {
@apply -mt-4 text-sm;
@apply text-sm;
}
.rw-cell-error,
.rw-form-error-wrapper {
@ -89,10 +86,10 @@
@apply mt-2 list-inside list-disc;
}
.rw-button {
@apply btn btn-primary font-inter
@apply btn font-inter hover:shadow-lg;
}
.rw-button.rw-button-small {
@apply rounded-sm px-2 py-1 text-xs;
@apply btn-sm;
}
.rw-button-icon {
@apply mr-1 text-xl leading-5;
@ -107,13 +104,16 @@
@apply mt-8;
}
.rw-label {
@apply mt-6 block text-left font-semibold text-gray-600 font-inter;
@apply mt-6 block text-left font-inter font-semibold text-gray-600;
}
.rw-label.rw-label-error {
@apply text-red-600;
}
.rw-input {
@apply mt-2 block w-full rounded border border-gray-200 bg-white p-2 outline-none font-inter;
@apply input input-bordered w-full max-w-xs font-inter;
}
.rw-textarea {
@apply textarea textarea-bordered font-inter max-w-xs w-full;
}
.rw-check-radio-items {
@apply flex justify-items-center;
@ -129,14 +129,14 @@
@apply border-gray-400;
}
.rw-input-error {
@apply border-red-600 text-red-600;
@apply input-error;
}
.rw-input-error:focus {
@apply border-red-600 outline-none;
box-shadow: 0 0 5px #c53030;
}
.rw-field-error {
@apply mt-1 block text-xs font-semibold text-red-600 font-inter text-left;
@apply my-3 block text-left font-inter text-xs font-semibold text-red-600;
}
.rw-table-wrapper-responsive {
@apply overflow-x-auto;
@ -182,25 +182,7 @@
@apply ml-0;
}
.rw-table-actions {
@apply flex h-4 items-center justify-end pr-1;
}
.rw-table-actions .rw-button {
@apply bg-transparent;
}
.rw-table-actions .rw-button:hover {
@apply bg-gray-500 text-white;
}
.rw-table-actions .rw-button-blue {
@apply text-blue-500;
}
.rw-table-actions .rw-button-blue:hover {
@apply bg-blue-500 text-white;
}
.rw-table-actions .rw-button-red {
@apply text-red-600;
}
.rw-table-actions .rw-button-red:hover {
@apply bg-red-600 text-white;
@apply flex h-4 items-center justify-end pr-1 space-x-2;
}
.rw-text-center {
@apply text-center;