diff --git a/app/web/src/components/IdeHeader/IdeHeader.tsx b/app/web/src/components/IdeHeader/IdeHeader.tsx index b9a34ca..a1f0bf7 100644 --- a/app/web/src/components/IdeHeader/IdeHeader.tsx +++ b/app/web/src/components/IdeHeader/IdeHeader.tsx @@ -95,16 +95,17 @@ const IdeHeader = ({
)}
- { (!children) - ? - : children - } + ) : ( + children + )} {/* Fork */}
@@ -117,88 +118,95 @@ const IdeHeader = ({ export default IdeHeader - -function DefaultTopButtons({ project, projectTitle, _projectOwner, handleRender, canEdit }) { - return (<> - {canEdit && !projectTitle && ( - ( - - - - )} - /> - )} - {!projectTitle && ( - - + {canEdit && !projectTitle && ( + ( + + + + )} /> - - )} - {projectTitle && ( - - navigate(routes.ide({ userName: _projectOwner, projectTitle })) - } - name="Editor" - > - - - )} - - {({ open }) => { - return ( - <> - - - - - - {open && ( - - + + + )} + {projectTitle && ( + + navigate(routes.ide({ userName: _projectOwner, projectTitle })) + } + name="Editor" + > + + + )} + + {({ open }) => { + return ( + <> + + - - - - - - + + + + {open && ( + + + + + + + + - - encoded script - external script - - - - )} - - ) - }} - - ) -} \ No newline at end of file + + encoded script + external script + + + + )} + + ) + }} + + + ) +} diff --git a/app/web/src/components/ImageUploader/ImageUploader.js b/app/web/src/components/ImageUploader/ImageUploader.js index a121d80..2980a2d 100644 --- a/app/web/src/components/ImageUploader/ImageUploader.js +++ b/app/web/src/components/ImageUploader/ImageUploader.js @@ -11,17 +11,24 @@ 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 = '' }) { +export function ImageFallback({ + width = 100, + imageId = 'CadHub/eia1kwru54g2kf02s2xx', + className = '', +}) { return ( -
- -
) +
+ +
+ ) } export default function ImageUploader({ @@ -82,10 +89,7 @@ export default function ImageUploader({ {cloudinaryId && isEditable && ( )} {isEditable && } diff --git a/app/web/src/components/KeyValue/KeyValue.tsx b/app/web/src/components/KeyValue/KeyValue.tsx index ed7c2d8..f05aeea 100644 --- a/app/web/src/components/KeyValue/KeyValue.tsx +++ b/app/web/src/components/KeyValue/KeyValue.tsx @@ -12,43 +12,46 @@ interface KeyValueType { } const KeyValue = ({ - keyName, - children, - hide = false, - canEdit = false, - onEdit, - isEditable = false, - bottom = false, - className = "", - } : KeyValueType) => { - if (!children || hide) return null - return ( -
-
- {keyName} - {canEdit && - (isEditable ? ( - - ) : ( - - ))} -
-
{children}
+ keyName, + children, + hide = false, + canEdit = false, + onEdit, + isEditable = false, + bottom = false, + className = '', +}: KeyValueType) => { + if (!children || hide) return null + return ( +
+
+ {keyName} + {canEdit && + (isEditable ? ( + + ) : ( + + ))}
- ) - } +
+ {children} +
+
+ ) +} - export default KeyValue \ No newline at end of file +export default KeyValue diff --git a/app/web/src/components/NavPlusButton/NavPlusButton.tsx b/app/web/src/components/NavPlusButton/NavPlusButton.tsx index 73ea57d..b5ea48f 100644 --- a/app/web/src/components/NavPlusButton/NavPlusButton.tsx +++ b/app/web/src/components/NavPlusButton/NavPlusButton.tsx @@ -52,7 +52,11 @@ const NavPlusButton: React.FC = () => { ' 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 ba6a615..f90ecf7 100644 --- a/app/web/src/components/ProfileSlashLogin/ProfileSlashLogin.tsx +++ b/app/web/src/components/ProfileSlashLogin/ProfileSlashLogin.tsx @@ -46,7 +46,8 @@ const ProfileSlashLogin = () => { + className="h-full w-full outline-none border-ch-gray-400 border-2 rounded-full" + > {!loading && ( { /> )} - { currentUser && ( - + {currentUser && ( +

Hello {user?.name} @@ -65,14 +66,18 @@ const ProfileSlashLogin = () => {
+ to={routes.user({ userName: user?.userName })} + >
View Your Profile
- + Logout - + )} ) : ( diff --git a/app/web/src/components/ProjectCard/ProjectCard.tsx b/app/web/src/components/ProjectCard/ProjectCard.tsx index bb446e8..9f6fbd4 100644 --- a/app/web/src/components/ProjectCard/ProjectCard.tsx +++ b/app/web/src/components/ProjectCard/ProjectCard.tsx @@ -34,7 +34,7 @@ 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 b3d1d26..d015a09 100644 --- a/app/web/src/components/ProjectProfile/ProjectProfile.tsx +++ b/app/web/src/components/ProjectProfile/ProjectProfile.tsx @@ -257,4 +257,3 @@ const ProjectProfile = ({ } export default ProjectProfile - diff --git a/app/web/src/components/UserProfile/UserProfile.tsx b/app/web/src/components/UserProfile/UserProfile.tsx index 7b18bfe..9f97fdc 100644 --- a/app/web/src/components/UserProfile/UserProfile.tsx +++ b/app/web/src/components/UserProfile/UserProfile.tsx @@ -4,18 +4,24 @@ 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 { fieldsConfig, fieldReducer, UserProfileType, FieldConfigType } from './userProfileConfig' +import { + fieldsConfig, + fieldReducer, + UserProfileType, + FieldConfigType, +} from './userProfileConfig' function buildFieldsConfig(fieldsConfig, user) { - Object.entries(fieldsConfig).forEach(([key, field] : [string, FieldConfigType]) => { - field.currentValue = field.newValue = user[key] - field.name = key - }) + Object.entries(fieldsConfig).forEach( + ([key, field]: [string, FieldConfigType]) => { + field.currentValue = field.newValue = user[key] + field.name = key + } + ) return fieldsConfig } - const UserProfile = ({ user, isEditable, @@ -23,11 +29,13 @@ const UserProfile = ({ onSave, error, projects, -} : UserProfileType) => { +}: UserProfileType) => { const { currentUser } = useAuth() const hasEditPermission = currentUser?.sub === user.id useEffect(() => { - isEditable && !hasEditPermission && navigate(routes.user({ userName: user.userName })) + isEditable && + !hasEditPermission && + navigate(routes.user({ userName: user.userName })) }, [currentUser]) const initializedFields = buildFieldsConfig(fieldsConfig, user) @@ -49,8 +57,7 @@ const UserProfile = ({ projectOwnerImage={user?.image} projectOwnerId={user?.id} > - - +
@@ -63,7 +70,7 @@ const UserProfile = ({
@@ -95,14 +102,14 @@ const UserProfile = ({ />

- +
{/* Viewer */}
-

Projects

+

+ Projects +

diff --git a/app/web/src/components/UserProfile/userProfileConfig.tsx b/app/web/src/components/UserProfile/userProfileConfig.tsx index a4c7574..666843b 100644 --- a/app/web/src/components/UserProfile/userProfileConfig.tsx +++ b/app/web/src/components/UserProfile/userProfileConfig.tsx @@ -5,149 +5,187 @@ import Editor from 'rich-markdown-editor' import ImageUploader from 'src/components/ImageUploader' import { User } from 'types/graphql' - export interface UserProfileType { - user: User, - isEditable: boolean, - loading: boolean, - error: boolean, - onSave: Function, - projects: {}[], + user: User + isEditable: boolean + loading: boolean + error: boolean + onSave: Function + projects: {}[] } export interface FieldConfigType { - name?: string, // introspection ugh - editable: boolean, - component?: ReactNode, - needsRef?: boolean, - isEditing?: boolean | undefined, - onSave?: Function, - currentValue?: any, - newValue?: any, + name?: string // introspection ugh + editable: boolean + component?: ReactNode + needsRef?: boolean + isEditing?: boolean | undefined + onSave?: Function + currentValue?: any + newValue?: any } -const ProfileKeyValue = ({ field, dispatch, user, save, hasEditPermission, children, bottom = false }) => { +const ProfileKeyValue = ({ + field, + dispatch, + user, + save, + hasEditPermission, + children, + bottom = false, +}) => { + return ( + { + if (field.isEditing) { + 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 }) + }} + isEditable={hasEditPermission && field.isEditing} + bottom={bottom} + className="mb-4" + > + {children} + + ) +} + +const bioField: FieldConfigType = { + editable: true, + needsRef: true, + component: (props) => { + const ref = useRef(null) + + const { dispatch, field } = props + return ( - { - if (field.isEditing) { - save(user.userName, { [field.name]: field.newValue }) + +
- { children } + onClick={(e) => + e?.target?.id === 'bio-wrap' && ref?.current?.focusAtEnd() + } + > + + dispatch({ + type: 'SET_NEW_VALUE', + payload: { field: field.bio, value: bio() }, + }) + } + /> +
+
+ ) + }, +} + +const createdAtField: FieldConfigType = { + editable: false, + component: (props) => { + const { field } = props + + return ( + +

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

) - } + }, +} -const bioField : FieldConfigType = { - editable: true, - needsRef: true, - component: (props) => { - const ref = useRef(null) +const imageField: FieldConfigType = { + editable: true, + component: (props) => { + const { field, user, save, hasEditPermission } = props + return ( + { + save(user.userName, { + image, + }) + }} + aspectRatio={1} + isEditable={hasEditPermission && !field.isEditing} + imageUrl={user.image} + width={300} + /> + ) + }, +} - const { dispatch, field } = props +const nameField: FieldConfigType = { + editable: true, + component: (props) => { + const { user, dispatch, field } = props - return -
+ {!field.isEditing ? ( +

{user?.name}

+ ) : ( + + dispatch({ + type: 'SET_NEW_VALUE', + payload: { field: field.name, value }, + }) } - onClick={(e) => - e?.target?.id === 'bio-wrap' && - ref?.current?.focusAtEnd() + isEditable={!field.isEditable} + /> + )} + + ) + }, +} + +const userNameField: FieldConfigType = { + editable: true, + component: (props) => { + const { dispatch, field } = props + + return ( + + {!field.isEditing ? ( +

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

+ ) : ( + + dispatch({ + type: 'SET_NEW_VALUE', + payload: { field: field.name, value }, + }) } - > - dispatch({ type: "SET_NEW_VALUE", payload: { field: field.bio, value: bio() }})} - /> -
-
- }, -} - -const createdAtField : FieldConfigType = { - editable: false, - component: (props) => { - const { field } = props - - return -

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

-
- }, -} - -const imageField : FieldConfigType = { - editable: true, - component: (props) => { - const { field, user, save, hasEditPermission } = props - return ( - { - save(user.userName, { - image, - }) - }} - aspectRatio={1} - isEditable={hasEditPermission && !field.isEditing} - imageUrl={user.image} - width={300} - /> - ) - }, -} - -const nameField : FieldConfigType = { - editable: true, - component: (props) => { - const { user, dispatch, field } = props - - return - { (!field.isEditing) - ?

{ user?.name }

- : dispatch({ type: "SET_NEW_VALUE", payload: { field: field.name, value }})} - isEditable={!field.isEditable} - /> - } -
- }, -} - -const userNameField : FieldConfigType = { - editable: true, - component: (props) => { - const { dispatch, field } = props - - return - { (!field.isEditing) - ?

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

- : dispatch({ type: "SET_NEW_VALUE", payload: { field: field.name, value }})} - isEditable={!field.isEditable} - /> - } -
- }, + isEditable={!field.isEditable} + /> + )} + + ) + }, } export const fieldsConfig = { @@ -166,24 +204,27 @@ export const fieldsConfig = { export function fieldReducer(state, action) { switch (action.type) { - case "TOGGLE_EDITING": + case 'TOGGLE_EDITING': return { ...state, [action.payload]: { ...state[action.payload], - isEditing: (state[action.payload].editable && !state[action.payload].isEditing) ? true : false, - } + isEditing: + state[action.payload].editable && !state[action.payload].isEditing + ? true + : false, + }, } - case "SET_NEW_VALUE": + case 'SET_NEW_VALUE': const newState = { ...state, [action.payload.field]: { ...state[action.payload.field], newValue: action.payload.value, - } + }, } return newState default: return state } -} \ No newline at end of file +} diff --git a/app/web/src/layouts/MainLayout/MainLayout.js b/app/web/src/layouts/MainLayout/MainLayout.js index 1050c47..811eff0 100644 --- a/app/web/src/layouts/MainLayout/MainLayout.js +++ b/app/web/src/layouts/MainLayout/MainLayout.js @@ -135,7 +135,8 @@ const MainLayout = ({ children, shouldRemoveFooterInIde }) => { + className="h-full w-full outline-none border-ch-gray-400 border-2 rounded-full" + > {!loading && ( { /> )} - { currentUser && ( - + {currentUser && ( +

Hello {user?.name} @@ -154,14 +155,18 @@ const MainLayout = ({ children, shouldRemoveFooterInIde }) => {
+ to={routes.user({ userName: user?.userName })} + >
View Your Profile
- + Logout - + )} diff --git a/app/web/src/pages/AccountRecoveryPage/AccountRecoveryPage.js b/app/web/src/pages/AccountRecoveryPage/AccountRecoveryPage.js index eb5a5b3..519e3bb 100644 --- a/app/web/src/pages/AccountRecoveryPage/AccountRecoveryPage.js +++ b/app/web/src/pages/AccountRecoveryPage/AccountRecoveryPage.js @@ -37,9 +37,7 @@ const AccountRecoveryPage = () => { className="grid items-center gap-2" style={{ gridTemplateColumns: 'auto 1fr' }} > - - email - + email { required: true, }} /> - - confirm - + confirm