diff --git a/app/web/config/tailwind.config.js b/app/web/config/tailwind.config.js index ea1ef82..90382d8 100644 --- a/app/web/config/tailwind.config.js +++ b/app/web/config/tailwind.config.js @@ -22,6 +22,7 @@ module.exports = { 800: '#1A1A1D', 750: '#222222', 760: '#232532', + 710: '#2B303C', // TODO: Use HSL so I stop adding grays to fix the warm/cool problem 700: '#2A3038', 600: '#3B3E4B', 550: '#63636A', @@ -66,6 +67,9 @@ module.exports = { gridAutoColumns: { 'preview-layout': 'minmax(30rem, 1fr) minmax(auto, 2fr)', }, + gridTemplateColumns: { + 'profile-layout': 'minmax(32rem, 1fr) 2fr', + }, keyframes: { 'bounce-sm': { '0%, 100%': { diff --git a/app/web/src/components/Hero/AssetWithGooey.tsx b/app/web/src/components/Hero/AssetWithGooey.tsx index 8a45ce7..dc8f83f 100644 --- a/app/web/src/components/Hero/AssetWithGooey.tsx +++ b/app/web/src/components/Hero/AssetWithGooey.tsx @@ -43,8 +43,7 @@ export default function AssetWithGooey({ + ) } @@ -73,22 +73,22 @@ function Gooey() { const dist = Math.random() * 3 + 2.5 const x = randomSign(Math.random() * dist) const y = randomSign(Math.sqrt(dist * dist - x * x)) - const z = randomSign(Math.random() * 3) + const z = randomSign(Math.random() * 2) const position: [number, number, number] = [x, z, y] const size = Math.random() * 0.8 + 0.1 - const distort = Math.random() * 0.8 + 0.1 - const speed = (Math.random() * 0.8) / size / size + 0.1 + const distort = (size > .1) ? Math.random() * .6 * size + 0.2 : 0 + const speed = (size > .1) ? (Math.random() * 0.8) / size / size + 0.1 : 0 return { position, size, distort, speed } }) const secondSet = Array.from({ length: 5 }).map((_, index) => { const dist = Math.random() * 3 + 1.5 const x = randomSign(Math.random() * dist) const y = randomSign(Math.sqrt(dist * dist - x * x)) - const z = randomSign(Math.random() * 3) + const z = randomSign(Math.random() * 2) const position: [number, number, number] = [x, z, y] const size = Math.random() * 0.2 + 0.05 - const distort = Math.random() * 0.8 + 0.1 - const speed = (Math.random() * 0.5) / size / size + 0.1 + const distort = (size > .1) ? Math.random() * .8 * size + 0.2 : 0 + const speed = (size > .1) ? (Math.random() * 0.5) / size / size + 0.1 : 0 return { position, size, distort, speed } }) return [...firstSet, ...secondSet] diff --git a/app/web/src/components/IdeHeader/IdeHeader.tsx b/app/web/src/components/IdeHeader/IdeHeader.tsx index f2199c5..7ca76a6 100644 --- a/app/web/src/components/IdeHeader/IdeHeader.tsx +++ b/app/web/src/components/IdeHeader/IdeHeader.tsx @@ -11,6 +11,7 @@ import ProfileSlashLogin from 'src/components/ProfileSlashLogin' import Gravatar from 'src/components/Gravatar/Gravatar' import EditableProjectTitle from 'src/components/EditableProjecTitle/EditableProjecTitle' import CaptureButton from 'src/components/CaptureButton/CaptureButton' +import { ReactNode } from 'react' const TopButton = ({ onClick, @@ -44,6 +45,7 @@ interface IdeHeaderProps { projectOwnerId?: string projectOwnerImage?: string projectId?: string + children?: ReactNode } const IdeHeader = ({ @@ -53,6 +55,7 @@ const IdeHeader = ({ projectOwnerImage, projectId, projectOwnerId, + children, }: IdeHeaderProps) => { const { currentUser } = useAuth() const { project } = useIdeContext() @@ -97,89 +100,19 @@ const IdeHeader = ({ )}
- {canEdit && !projectTitle && ( - ( - - - - )} /> + ) : ( + children )} - {!projectTitle && ( - - - - )} - {projectTitle && ( - - navigate(routes.ide({ userName: _projectOwner, projectTitle })) - } - name="Editor" - > - - - )} - - - {({ open }) => { - return ( - <> - - - - - - {open && ( - - - - - - - - - - - encoded script - external script - - - - )} - - ) - }} - {/* Fork */} -
+
@@ -189,3 +122,96 @@ const IdeHeader = ({ } export default IdeHeader + +function DefaultTopButtons({ + project, + projectTitle, + _projectOwner, + handleRender, + canEdit, +}) { + return ( + <> + {canEdit && !projectTitle && ( + ( + + + + )} + /> + )} + {!projectTitle && ( + + + + )} + {projectTitle && ( + + navigate(routes.ide({ userName: _projectOwner, projectTitle })) + } + name="Editor" + > + + + )} + + {({ open }) => { + return ( + <> + + + + + + {open && ( + + + + + + + + + + + encoded script + external script + + + + )} + + ) + }} + + + ) +} diff --git a/app/web/src/components/ImageUploader/ImageUploader.js b/app/web/src/components/ImageUploader/ImageUploader.js index d61f67a..ce96622 100644 --- a/app/web/src/components/ImageUploader/ImageUploader.js +++ b/app/web/src/components/ImageUploader/ImageUploader.js @@ -11,6 +11,26 @@ import Svg from 'src/components/Svg' const CLOUDINARY_UPLOAD_PRESET = 'CadHub_project_images' const CLOUDINARY_UPLOAD_URL = 'https://api.cloudinary.com/v1_1/irevdev/upload' +export function ImageFallback({ + width = 100, + imageId = 'CadHub/eia1kwru54g2kf02s2xx', + className = '', +}) { + return ( +
+ +
+ ) +} + export default function ImageUploader({ onImageUpload = () => {}, imageUrl, @@ -65,36 +85,24 @@ export default function ImageUploader({ } style={{ paddingBottom: `${(1 / aspectRatio) * 100}%` }} > -
+
{cloudinaryId && isEditable && ( - )} {isEditable && } {(cloudinaryId || !isEditable) && ( -
- -
+ )} {!cloudinaryId && } {!cloudinaryId && isEditable && ( -
-
- Drop files here ... or{' '} - - +
+
+ Drop files here or{' '} + + upload diff --git a/app/web/src/components/InputText/InputText.js b/app/web/src/components/InputText/InputText.js index 30e447a..4f4cd3b 100644 --- a/app/web/src/components/InputText/InputText.js +++ b/app/web/src/components/InputText/InputText.js @@ -23,7 +23,7 @@ const InputText = ({ )} /> { <>
{ console.error('Field declared editable without edit action.') }, + isEditing = false, +} : EditToggleType) => ( + (isEditing ? ( + + ) : ( + + )) +) + +interface KeyValueType { + keyName: string + children: React.ReactNode + bottom?: boolean + className?: string + edit?: EditToggleType +} + +const KeyValue = ({ + keyName, + children, + bottom = false, + className = '', + edit = { hasPermissionToEdit: false }, +}: KeyValueType) => { + if (!children) return null + return ( +
+
+ {keyName} + {edit && edit.hasPermissionToEdit && } +
+
+ {children} +
+
+ ) +} + +export default KeyValue diff --git a/app/web/src/components/NavPlusButton/NavPlusButton.tsx b/app/web/src/components/NavPlusButton/NavPlusButton.tsx index 7298c27..b5ea48f 100644 --- a/app/web/src/components/NavPlusButton/NavPlusButton.tsx +++ b/app/web/src/components/NavPlusButton/NavPlusButton.tsx @@ -40,8 +40,9 @@ const NavPlusButton: React.FC = () => { - +

New Project

+
    {menuOptions.map(({ name, sub, ideType, bgClasses, dotClasses }) => (
  • { ' px-4 py-1 my-4 bg-opacity-30 hover:bg-opacity-70 grid grid-flow-col-dense items-center gap-2' } > -
    +
    {name}
    {sub}
    diff --git a/app/web/src/components/ProfileSlashLogin/ProfileSlashLogin.tsx b/app/web/src/components/ProfileSlashLogin/ProfileSlashLogin.tsx index 22c0b8e..055eeed 100644 --- a/app/web/src/components/ProfileSlashLogin/ProfileSlashLogin.tsx +++ b/app/web/src/components/ProfileSlashLogin/ProfileSlashLogin.tsx @@ -2,7 +2,8 @@ import { useState } from 'react' import { useAuth } from '@redwoodjs/auth' import { Link, routes } from '@redwoodjs/router' import ReactGA from 'react-ga' -import Popover from '@material-ui/core/Popover' +import { Popover } from '@headlessui/react' +import { ImageFallback } from 'src/components/ImageUploader' import useUser from 'src/helpers/hooks/useUser' import LoginModal from 'src/components/LoginModal' @@ -42,60 +43,54 @@ const ProfileSlashLogin = () => { return (
    {isAuthenticated ? ( -
    - -
    + {!loading && ( + + )} + + {currentUser && ( + + +

    + Hello {user?.name} +

    + +
    + +
    View Your Profile
    + + + Logout + +
    + )} + ) : ( )} - {isAuthenticated && currentUser && ( - -
    - -

    - Hello {user?.name} -

    - -
    -
    - -
    Your Profile
    - - - Logout - -
    -
    - )} setIsLoginModalOpen(false)} diff --git a/app/web/src/components/ProjectCard/ProjectCard.tsx b/app/web/src/components/ProjectCard/ProjectCard.tsx index 374c1c7..fa0f303 100644 --- a/app/web/src/components/ProjectCard/ProjectCard.tsx +++ b/app/web/src/components/ProjectCard/ProjectCard.tsx @@ -4,10 +4,11 @@ import CadPackage from 'src/components/CadPackage/CadPackage' import { countEmotes } from 'src/helpers/emote' import ImageUploader from 'src/components/ImageUploader' +import { ImageFallback } from '../ImageUploader/ImageUploader' const ProjectCard = ({ title, mainImage, user, Reaction, cadPackage }) => (
  • (
-
diff --git a/app/web/src/components/ProjectProfile/ProjectProfile.tsx b/app/web/src/components/ProjectProfile/ProjectProfile.tsx index d04835d..3d4c83b 100644 --- a/app/web/src/components/ProjectProfile/ProjectProfile.tsx +++ b/app/web/src/components/ProjectProfile/ProjectProfile.tsx @@ -17,51 +17,7 @@ import { useIdeInit } from 'src/components/EncodedUrl/helpers' import ProfileViewer from '../ProfileViewer/ProfileViewer' import Svg from 'src/components/Svg/Svg' import OpenscadStaticImageMessage from 'src/components/OpenscadStaticImageMessage/OpenscadStaticImageMessage' - -const KeyValue = ({ - keyName, - children, - hide = false, - canEdit = false, - onEdit, - isEditable = false, -}: { - keyName: string - children: React.ReactNode - hide?: boolean - canEdit?: boolean - onEdit?: () => void - isEditable?: boolean -}) => { - if (!children || hide) return null - return ( -
-
- {keyName} - {canEdit && - (isEditable ? ( - - ) : ( - - ))} -
-
{children}
-
- ) -} +import KeyValue from 'src/components/KeyValue/KeyValue' const ProjectProfile = ({ userProject, @@ -71,7 +27,7 @@ const ProjectProfile = ({ onComment, }) => { const [comment, setComment] = useState('') - const [isEditable, setIsEditable] = useState(false) + const [isEditing, setIsEditing] = useState(false) const onCommentClear = () => { onComment(comment) setComment('') @@ -80,14 +36,14 @@ const ProjectProfile = ({ const [isReactionsModalOpen, setIsReactionsModalOpen] = useState(false) const { currentUser } = useAuth() const editorRef = useRef(null) - const canEdit = + const hasPermissionToEdit = currentUser?.sub === userProject.id || currentUser?.roles.includes('admin') const project = userProject?.Project const emotes = countEmotes(project?.Reaction) const userEmotes = project?.userReactions.map(({ emote }) => emote) useEffect(() => { - isEditable && - !canEdit && + isEditing && + !hasPermissionToEdit && navigate( routes.project({ userName: userProject.userName, @@ -99,7 +55,7 @@ const ProjectProfile = ({ const [newDescription, setNewDescription] = useState(project?.description) const onDescriptionChange = (description) => setNewDescription(description()) const onEditSaveClick = () => { - if (isEditable) { + if (isEditing) { onSave(project?.id, { description: newDescription }) return } @@ -140,7 +96,7 @@ const ProjectProfile = ({
{/* Side panel */} -
+

{project?.title.replace(/-/g, ' ')} @@ -152,26 +108,27 @@ const ProjectProfile = ({ className="px-3 py-2 rounded" />

- { - if (!isEditable) { - setIsEditable(true) - } else { - onEditSaveClick() - setIsEditable(false) - } + edit={{ + hasPermissionToEdit, + isEditing, + onEdit: () => { + if (!isEditing) { + setIsEditing(true) + } else { + onEditSaveClick() + setIsEditing(false) + } + }, }} - isEditable={isEditable} >
e?.target?.id === 'description-wrap' && @@ -181,11 +138,11 @@ const ProjectProfile = ({
-
+ }
{new Date(project?.createdAt).toDateString()} @@ -200,10 +157,11 @@ const ProjectProfile = ({ userEmotes={userEmotes} onEmote={onReaction} onShowProjectReactions={() => setIsReactionsModalOpen(true)} + className="" /> - - {!isEditable && ( + { currentUser && + {!isEditing && ( <> {currentUser && ( <> @@ -259,8 +217,8 @@ const ProjectProfile = ({ )} - - {canEdit && ( + } + {hasPermissionToEdit && ( <>

Danger Zone

// TODO replace pencil with a save icon - ) : canEdit ? ( - - ) : null} -
-
-
-

Bio:

-
- - setInput({ - ...input, - bio: bioFn(), - }) - } - /> -
-
-
-

Projects:

- -
- - - ) -} - -export default UserProfile diff --git a/app/web/src/components/UserProfile/UserProfile.tsx b/app/web/src/components/UserProfile/UserProfile.tsx new file mode 100644 index 0000000..7c300f7 --- /dev/null +++ b/app/web/src/components/UserProfile/UserProfile.tsx @@ -0,0 +1,131 @@ +import { useEffect, useReducer } from 'react' +import { useAuth } from '@redwoodjs/auth' +import { Link, navigate, routes } from '@redwoodjs/router' +import ProjectsOfUser from 'src/components/ProjectsOfUserCell' +import IdeHeader from 'src/components/IdeHeader/IdeHeader' +import Svg from 'src/components/Svg/Svg' +import { + fieldComponents, + fieldReducer, + UserProfileType, + FieldType, +} from './userProfileConfig' + +// This function initializes the state management object for each of the fields +function buildFieldsConfig(fieldsConfig, user, hasPermissionToEdit) { + return Object.fromEntries(Object.keys(fieldsConfig).map( + (key: string): [string, FieldType] => ([key, { + name: key, + currentValue: user[key], + newValue: user[key], + isEditing: false, + hasPermissionToEdit, + }]) + )) +} + +const UserProfile = ({ + user, + isEditing, + loading, + onSave, + error, +}: UserProfileType) => { + const { currentUser } = useAuth() + const hasPermissionToEdit = currentUser?.sub === user.id + useEffect(() => { + isEditing && + !hasPermissionToEdit && + navigate(routes.user({ userName: user.userName })) + }, [currentUser]) + + const initializedFields = buildFieldsConfig(fieldComponents, user, hasPermissionToEdit) + const [fields, fieldDispatch] = useReducer(fieldReducer, initializedFields) + const { + name: NameField, + userName: UserNameField, + image: ImageField, + bio: BioField, + createdAt: MemberSinceField, + } = fieldComponents + + return ( + <> +
+
+ + + + {}} + projectOwner={user?.userName} + projectOwnerImage={user?.image} + projectOwnerId={user?.id} + > + + +
+
+
+ {/* Side panel */} +
+
+ {!isEditing && ( +
+ +
+ )} +
+ + +
+
+
+ +
+
+ +
+
+ {/* Viewer */} +
+

+ Projects +

+ +
+
+
+
+ + ) +} + +export default UserProfile diff --git a/app/web/src/components/UserProfile/userProfileConfig.tsx b/app/web/src/components/UserProfile/userProfileConfig.tsx new file mode 100644 index 0000000..cda4689 --- /dev/null +++ b/app/web/src/components/UserProfile/userProfileConfig.tsx @@ -0,0 +1,216 @@ +import React, { ReactNode, useRef } from 'react' +import KeyValue from 'src/components/KeyValue/KeyValue' +import InputText from '../InputText/InputText' +import Editor from 'rich-markdown-editor' +import ImageUploader from 'src/components/ImageUploader' +import { User } from 'types/graphql' + +export const fieldComponents = { + name: NameField, + userName: UserNameField, + image: ImageField, + bio: BioField, + createdAt: MemberSinceField, +} + +export interface UserProfileType { + user: User + isEditing: boolean + loading: boolean + error: boolean + onSave: Function + projects: {}[] +} + +export interface FieldType { + name: string + currentValue: any + newValue: any + isEditing: boolean + hasPermissionToEdit: boolean +} + +export interface FieldComponentPropsType { + field: FieldType + dispatch?: React.Dispatch + user?: User + save?: Function + hasPermissionToEdit?: boolean +} + +interface ProfileKeyValueType extends FieldComponentPropsType { + children: ReactNode + bottom: boolean +} + +const ProfileKeyValue = ({ + field, + dispatch, + user, + save, + hasPermissionToEdit, + children, + bottom = false, +} : ProfileKeyValueType) => { + return ( + (user[field.name] && hasPermissionToEdit) && { + if (field.isEditing && field.currentValue !== field.newValue) { + save(user.userName, { [field.name]: field.newValue }) + } + dispatch({ + type: 'SET_CURRENT_VALUE', + payload: { field: field.name, value: field.newValue }, + }) + dispatch({ type: 'TOGGLE_EDITING', payload: field.name }) + }, + }} + bottom={bottom} + className="mb-4" + > + {children} + + ) +} + +function BioField(props) { + const ref = useRef(null) + const { field, dispatch } = props + + return ( + +
+ e?.target?.id === 'bio-wrap' && ref?.current?.focusAtEnd() + } + > + + dispatch({ + type: 'SET_NEW_VALUE', + payload: { field: 'bio', value: bio() }, + }) + } + /> +
+
+ ) +} + +function MemberSinceField(props : FieldComponentPropsType) { + return ( + +

+ {new Date(props.field.currentValue).toLocaleDateString()} +

+
+ ) +} + +function ImageField(props : FieldComponentPropsType) { + const { field, user, save, hasPermissionToEdit } = props + return ( + { + save(user.userName, { + image, + }) + }} + aspectRatio={1} + isEditable={hasPermissionToEdit} + imageUrl={user.image} + width={300} + /> + ) +} + +function NameField(props : FieldComponentPropsType) { + const { user, dispatch, field } = props + + return ( + + {!field.isEditing ? ( +

{user?.name}

+ ) : ( + + dispatch({ + type: 'SET_NEW_VALUE', + payload: { field: 'name', value }, + }) + } + isEditable={field.isEditing} + /> + )} +
+ ) +} + +function UserNameField(props : FieldComponentPropsType) { + const { dispatch, field } = props + + return ( + + {!field.isEditing ? ( +

+ @{field?.currentValue?.replace(/([^a-zA-Z\d_:])/g, '-')} +

+ ) : ( + + dispatch({ + type: 'SET_NEW_VALUE', + payload: { field: 'userName', value }, + }) + } + isEditable={field.isEditing} + /> + )} +
+ ) +} + +export function fieldReducer(state, action) { + switch (action.type) { + case 'TOGGLE_EDITING': + return { + ...state, + [action.payload]: { + ...state[action.payload], + isEditing: + state[action.payload].hasPermissionToEdit && !state[action.payload].isEditing + ? true + : false, + }, + } + case 'SET_NEW_VALUE': + const newState = { + ...state, + [action.payload.field]: { + ...state[action.payload.field], + newValue: action.payload.value, + }, + } + return newState + default: + return state + } +} diff --git a/app/web/src/index.css b/app/web/src/index.css index fe08112..aa01fce 100644 --- a/app/web/src/index.css +++ b/app/web/src/index.css @@ -18,6 +18,18 @@ font-family: 'Fira Sans', ui-sans-serif, system-ui, -apple-system, system-ui, "Segoe UI", "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; } + .ch-scrollbar::-webkit-scrollbar { + @apply w-3; + } + + .ch-scrollbar::-webkit-scrollbar-track { + @apply bg-ch-gray-700; + } + + .ch-scrollbar::-webkit-scrollbar-thumb { + @apply bg-ch-pink-800 bg-opacity-30 hover:bg-opacity-60; + } + /* https://www.a11yproject.com/posts/2013-01-11-how-to-hide-content/ */ .visually-hidden { clip: rect(0 0 0 0); @@ -39,6 +51,7 @@ } .tabToggle.disabled { @apply text-ch-gray-550 cursor-not-allowed; + } } diff --git a/app/web/src/layouts/MainLayout/MainLayout.js b/app/web/src/layouts/MainLayout/MainLayout.js index aa24058..811eff0 100644 --- a/app/web/src/layouts/MainLayout/MainLayout.js +++ b/app/web/src/layouts/MainLayout/MainLayout.js @@ -3,7 +3,7 @@ import { Link, routes, navigate } from '@redwoodjs/router' import { useAuth } from '@redwoodjs/auth' import { Toaster, toast } from '@redwoodjs/web/toast' import Tooltip from '@material-ui/core/Tooltip' -import Popover from '@material-ui/core/Popover' +import { Popover } from '@headlessui/react' import { getActiveClasses } from 'get-active-classes' import Footer from 'src/components/Footer' import { useLocation } from '@redwoodjs/router' @@ -13,7 +13,7 @@ import ReactGA from 'react-ga' import { isBrowser } from '@redwoodjs/prerender/browserUtils' import Svg from 'src/components/Svg' -import ImageUploader from 'src/components/ImageUploader' +import { ImageFallback } from 'src/components/ImageUploader' import useUser from 'src/helpers/hooks/useUser' let previousSubmission = '' @@ -91,7 +91,7 @@ const MainLayout = ({ children, shouldRemoveFooterInIde }) => { } }, [hash, client]) return ( -
+
@@ -197,7 +189,7 @@ const MainLayout = ({ children, shouldRemoveFooterInIde }) => { open={isLoginModalOpen} onClose={() => setIsLoginModalOpen(false)} /> -
{children}
+
{children}
{!shouldRemoveFooterInIde &&
}
) diff --git a/app/web/src/pages/AccountRecoveryPage/AccountRecoveryPage.js b/app/web/src/pages/AccountRecoveryPage/AccountRecoveryPage.js index b585671..519e3bb 100644 --- a/app/web/src/pages/AccountRecoveryPage/AccountRecoveryPage.js +++ b/app/web/src/pages/AccountRecoveryPage/AccountRecoveryPage.js @@ -31,15 +31,13 @@ const AccountRecoveryPage = () => { />
-

Send recovery email

+

Send recovery email

- - email: - + email { }, }} /> + + Send email +
- - Send email -
diff --git a/app/web/src/pages/EditUserPage/EditUserPage.js b/app/web/src/pages/EditUserPage/EditUserPage.js index 23623a9..3d52cc3 100644 --- a/app/web/src/pages/EditUserPage/EditUserPage.js +++ b/app/web/src/pages/EditUserPage/EditUserPage.js @@ -1,14 +1,13 @@ -import MainLayout from 'src/layouts/MainLayout' import EditUserCell from 'src/components/EditUserCell' import Seo from 'src/components/Seo/Seo' const UserPage = ({ userName }) => { return ( - + <> - + ) } diff --git a/app/web/src/pages/HomePage/HomePage.tsx b/app/web/src/pages/HomePage/HomePage.tsx index e215150..f4d49c2 100644 --- a/app/web/src/pages/HomePage/HomePage.tsx +++ b/app/web/src/pages/HomePage/HomePage.tsx @@ -6,10 +6,10 @@ const ProjectsPage = () => { return ( diff --git a/app/web/src/pages/ProjectsPage/ProjectsPage.tsx b/app/web/src/pages/ProjectsPage/ProjectsPage.tsx index 1fcaa66..cf27a11 100644 --- a/app/web/src/pages/ProjectsPage/ProjectsPage.tsx +++ b/app/web/src/pages/ProjectsPage/ProjectsPage.tsx @@ -8,7 +8,7 @@ const ProjectsPage = () => {
diff --git a/app/web/src/pages/UpdatePasswordPage/UpdatePasswordPage.js b/app/web/src/pages/UpdatePasswordPage/UpdatePasswordPage.js index 996e53e..4e4ad16 100644 --- a/app/web/src/pages/UpdatePasswordPage/UpdatePasswordPage.js +++ b/app/web/src/pages/UpdatePasswordPage/UpdatePasswordPage.js @@ -32,14 +32,14 @@ const UpdatePasswordPage = () => {
-

Reset Password

+

Reset Password

- - password: + + password { required: true, }} /> - - confirm: - + confirm { required: true, }} /> + + Update +
- - Update -
diff --git a/app/web/src/pages/UserPage/UserPage.js b/app/web/src/pages/UserPage/UserPage.js index c2b027b..661d770 100644 --- a/app/web/src/pages/UserPage/UserPage.js +++ b/app/web/src/pages/UserPage/UserPage.js @@ -1,14 +1,16 @@ import MainLayout from 'src/layouts/MainLayout' import EditUserCell from 'src/components/EditUserCell' import Seo from 'src/components/Seo/Seo' +import { Toaster } from '@redwoodjs/web/toast' const UserPage = ({ userName }) => { return ( - + <> + - + ) }