diff --git a/api/src/functions/identity-signup.js b/api/src/functions/identity-signup.js
index b9f3460..ee6fa0a 100644
--- a/api/src/functions/identity-signup.js
+++ b/api/src/functions/identity-signup.js
@@ -68,11 +68,12 @@ export const handler = async (req, _context) => {
const isUnique = !(await db.user.findOne({
where: { userName: seed },
}))
- if(isUnique) {
+ if (isUnique) {
return seed
}
count += 1
- const newSeed = count === 1 ? `${seed}_${count}` : seed.slice(0,-1) + count
+ const newSeed =
+ count === 1 ? `${seed}_${count}` : seed.slice(0, -1) + count
return generateUniqueUserName(newSeed, count)
}
const userNameSeed = enforceAlphaNumeric(email.split('@')[0])
@@ -83,7 +84,7 @@ export const handler = async (req, _context) => {
name: user.user_metadata && user.user_metadata.full_name,
id: user.id,
}
- await createUserInsecure({input})
+ await createUserInsecure({ input })
return {
statusCode: 200,
diff --git a/api/src/graphql/parts.sdl.js b/api/src/graphql/parts.sdl.js
index a7f42e4..31dd970 100644
--- a/api/src/graphql/parts.sdl.js
+++ b/api/src/graphql/parts.sdl.js
@@ -16,7 +16,7 @@ export const schema = gql`
type Query {
parts: [Part!]!
part(id: String!): Part
- partByUserAndTitle(userName: String! partTitle: String!): Part
+ partByUserAndTitle(userName: String!, partTitle: String!): Part
}
input CreatePartInput {
diff --git a/api/src/lib/auth.js b/api/src/lib/auth.js
index 3889bbc..9fbd050 100644
--- a/api/src/lib/auth.js
+++ b/api/src/lib/auth.js
@@ -142,7 +142,7 @@ export const requireAuth = ({ role } = {}) => {
throw new ForbiddenError("You don't have access to do that.")
}
- if(context.currentUser?.sub === '5cea3906-1e8e-4673-8f0d-89e6a963c096') {
+ if (context.currentUser?.sub === '5cea3906-1e8e-4673-8f0d-89e6a963c096') {
throw new ForbiddenError("That's a local admin ONLY.")
}
}
diff --git a/api/src/lib/owner.js b/api/src/lib/owner.js
index 086deeb..dc60aff 100644
--- a/api/src/lib/owner.js
+++ b/api/src/lib/owner.js
@@ -7,37 +7,38 @@ export const requireOwnership = async ({ userId, userName, partId } = {}) => {
if (!context.currentUser) {
throw new AuthenticationError("You don't have permission to do that.")
}
- if(!userId && !userName && !partId) {
+ if (!userId && !userName && !partId) {
throw new ForbiddenError("You don't have access to do that.")
}
- if(context.currentUser.roles?.includes('admin')) {
+ if (context.currentUser.roles?.includes('admin')) {
return
}
const netlifyUserId = context.currentUser?.sub
- if(userId && userId !== netlifyUserId) {
+ if (userId && userId !== netlifyUserId) {
throw new ForbiddenError("You don't own this resource.")
}
- if(userName) {
+ if (userName) {
const user = await db.user.findOne({
where: { userName },
})
- if(!user || user.id !== netlifyUserId) {
+ if (!user || user.id !== netlifyUserId) {
throw new ForbiddenError("You don't own this resource.")
}
}
- if(partId) {
- const user = await db.part.findOne({
- where: { id: partId },
- }).user()
+ if (partId) {
+ const user = await db.part
+ .findOne({
+ where: { id: partId },
+ })
+ .user()
- if(!user || user.id !== netlifyUserId) {
+ if (!user || user.id !== netlifyUserId) {
throw new ForbiddenError("You don't own this resource.")
}
}
-
}
diff --git a/api/src/services/helpers.js b/api/src/services/helpers.js
index d6e21f3..c5611eb 100644
--- a/api/src/services/helpers.js
+++ b/api/src/services/helpers.js
@@ -12,4 +12,5 @@ export const foreignKeyReplacement = (input) => {
return output
}
-export const enforceAlphaNumeric = (string) => string.replace(/([^a-zA-Z\d_:])/g, '-')
+export const enforceAlphaNumeric = (string) =>
+ string.replace(/([^a-zA-Z\d_:])/g, '-')
diff --git a/api/src/services/partReactions/partReactions.js b/api/src/services/partReactions/partReactions.js
index 4efd545..9116014 100644
--- a/api/src/services/partReactions/partReactions.js
+++ b/api/src/services/partReactions/partReactions.js
@@ -18,20 +18,24 @@ export const partReaction = ({ id }) => {
export const togglePartReaction = async ({ input }) => {
// if write fails emote_userId_partId @@unique constraint, then delete it instead
requireAuth()
- await requireOwnership({userId: input?.userId})
+ await requireOwnership({ userId: input?.userId })
const legalReactions = ['❤️', '👍', '😄', '🙌'] // TODO figure out a way of sharing code between FE and BE, so this is consistent with web/src/components/EmojiReaction/EmojiReaction.js
- if(!legalReactions.includes(input.emote)) {
- throw new UserInputError(`You can't react with '${input.emote}', only the following are allowed: ${legalReactions.join(', ')}`)
+ if (!legalReactions.includes(input.emote)) {
+ throw new UserInputError(
+ `You can't react with '${
+ input.emote
+ }', only the following are allowed: ${legalReactions.join(', ')}`
+ )
}
let dbPromise
- const inputClone = {...input} // TODO foreignKeyReplacement mutates input, which I should fix but am lazy right now
- try{
+ const inputClone = { ...input } // TODO foreignKeyReplacement mutates input, which I should fix but am lazy right now
+ try {
dbPromise = await db.partReaction.create({
data: foreignKeyReplacement(input),
})
- } catch(e) {
+ } catch (e) {
dbPromise = db.partReaction.delete({
- where: { emote_userId_partId: inputClone},
+ where: { emote_userId_partId: inputClone },
})
}
return dbPromise
diff --git a/api/src/services/parts/parts.js b/api/src/services/parts/parts.js
index 260442c..aad2a72 100644
--- a/api/src/services/parts/parts.js
+++ b/api/src/services/parts/parts.js
@@ -1,5 +1,8 @@
import { db } from 'src/lib/db'
-import { foreignKeyReplacement, enforceAlphaNumeric } from 'src/services/helpers'
+import {
+ foreignKeyReplacement,
+ enforceAlphaNumeric,
+} from 'src/services/helpers'
import { requireAuth } from 'src/lib/auth'
import { requireOwnership } from 'src/lib/owner'
@@ -15,15 +18,15 @@ export const part = ({ id }) => {
export const partByUserAndTitle = async ({ userName, partTitle }) => {
const user = await db.user.findOne({
where: {
- userName
- }
+ userName,
+ },
})
return db.part.findOne({
where: {
title_userId: {
title: partTitle,
userId: user.id,
- }
+ },
},
})
}
@@ -37,8 +40,8 @@ export const createPart = async ({ input }) => {
export const updatePart = async ({ id, input }) => {
requireAuth()
- await requireOwnership({partId: id})
- if(input.title) {
+ await requireOwnership({ partId: id })
+ if (input.title) {
input.title = enforceAlphaNumeric(input.title)
}
return db.part.update({
@@ -59,5 +62,7 @@ export const Part = {
Comment: (_obj, { root }) =>
db.part.findOne({ where: { id: root.id } }).Comment(),
Reaction: (_obj, { root }) =>
- db.part.findOne({ where: { id: root.id } }).Reaction({where: {userId: _obj.userId}}),
+ db.part
+ .findOne({ where: { id: root.id } })
+ .Reaction({ where: { userId: _obj.userId } }),
}
diff --git a/api/src/services/users/users.js b/api/src/services/users/users.js
index c06e1bf..4292baa 100644
--- a/api/src/services/users/users.js
+++ b/api/src/services/users/users.js
@@ -23,7 +23,7 @@ export const userName = ({ userName }) => {
export const createUser = ({ input }) => {
requireAuth({ role: 'admin' })
- createUserInsecure({input})
+ createUserInsecure({ input })
}
export const createUserInsecure = ({ input }) => {
return db.user.create({
@@ -41,12 +41,15 @@ export const updateUser = ({ id, input }) => {
export const updateUserByUserName = async ({ userName, input }) => {
requireAuth()
- await requireOwnership({userName})
- if(input.userName) {
+ await requireOwnership({ userName })
+ if (input.userName) {
input.userName = enforceAlphaNumeric(input.userName)
}
- if(input.userName && ['new', 'edit', 'update'].includes(input.userName)) { //TODO complete this and use a regexp so that it's not case sensitive, don't want someone with the userName eDiT
- throw new UserInputError(`You've tried to used a protected word as you userName, try something other than `)
+ if (input.userName && ['new', 'edit', 'update'].includes(input.userName)) {
+ //TODO complete this and use a regexp so that it's not case sensitive, don't want someone with the userName eDiT
+ throw new UserInputError(
+ `You've tried to used a protected word as you userName, try something other than `
+ )
}
return db.user.update({
data: input,
@@ -63,10 +66,16 @@ export const deleteUser = ({ id }) => {
export const User = {
Parts: (_obj, { root }) => db.user.findOne({ where: { id: root.id } }).Part(),
- Part: (_obj, { root, ...rest }) => _obj.partTitle && db.part.findOne({where: { title_userId: {
- title: _obj.partTitle,
- userId: root.id,
- }}}),
+ Part: (_obj, { root, ...rest }) =>
+ _obj.partTitle &&
+ db.part.findOne({
+ where: {
+ title_userId: {
+ title: _obj.partTitle,
+ userId: root.id,
+ },
+ },
+ }),
Reaction: (_obj, { root }) =>
db.user.findOne({ where: { id: root.id } }).Reaction(),
Comment: (_obj, { root }) =>
diff --git a/package.json b/package.json
index 8f4dc54..ea70fa9 100644
--- a/package.json
+++ b/package.json
@@ -14,15 +14,7 @@
"@redwoodjs/core": "^0.19.2"
},
"eslintConfig": {
- "extends": "@redwoodjs/eslint-config",
- "workingDirectories": [
- "./api",
- "./web/src/components",
- "./web/src/layouts",
- "./web/src/pages",
- "./web/src/index.js",
- "./web/src/Routes.js"
- ]
+ "extends": "@redwoodjs/eslint-config"
},
"engines": {
"node": ">=12",
diff --git a/web/src/components/Breadcrumb/Breadcrumb.js b/web/src/components/Breadcrumb/Breadcrumb.js
index fe921fb..1057db4 100644
--- a/web/src/components/Breadcrumb/Breadcrumb.js
+++ b/web/src/components/Breadcrumb/Breadcrumb.js
@@ -1,20 +1,31 @@
-import { getActiveClasses } from "get-active-classes"
+import { getActiveClasses } from 'get-active-classes'
import InputText from 'src/components/InputText'
const Breadcrumb = ({ userName, partTitle, onPartTitleChange, className }) => {
return (
-
- .
-
+
+
+ .
+
+
{userName}
- .
+
+ .
+
)
diff --git a/web/src/components/Button/Button.js b/web/src/components/Button/Button.js
index 5d76f0f..28b1056 100644
--- a/web/src/components/Button/Button.js
+++ b/web/src/components/Button/Button.js
@@ -1,21 +1,31 @@
import { getActiveClasses } from 'get-active-classes'
import Svg from 'src/components/Svg'
-const Button = ({onClick, iconName, children, className, shouldAnimateHover, disabled}) => {
+const Button = ({
+ onClick,
+ iconName,
+ children,
+ className,
+ shouldAnimateHover,
+ disabled,
+}) => {
return (
-
- {children}
-
-
+
+ {children}
+
+
)
}
diff --git a/web/src/components/Button/Button.stories.js b/web/src/components/Button/Button.stories.js
index 7d95d2d..115369e 100644
--- a/web/src/components/Button/Button.stories.js
+++ b/web/src/components/Button/Button.stories.js
@@ -1,10 +1,12 @@
import Button from './Button'
export const generated = () => {
- return <>
- button with icon
- click Me
- >
+ return (
+ <>
+ button with icon
+ click Me
+ >
+ )
}
export default { title: 'Components/Button' }
diff --git a/web/src/components/EditUser2Cell/EditUser2Cell.js b/web/src/components/EditUser2Cell/EditUser2Cell.js
index 850f260..94a7d24 100644
--- a/web/src/components/EditUser2Cell/EditUser2Cell.js
+++ b/web/src/components/EditUser2Cell/EditUser2Cell.js
@@ -35,8 +35,8 @@ export const Failure = ({ error }) => Error: {error.message}
export const Success = ({ user }) => {
const { addMessage } = useFlash()
const [updateUser, { loading, error }] = useMutation(UPDATE_USER_MUTATION, {
- onCompleted: ({updateUserByUserName}) => {
- navigate(routes.user2({userName: updateUserByUserName.userName}))
+ onCompleted: ({ updateUserByUserName }) => {
+ navigate(routes.user2({ userName: updateUserByUserName.userName }))
addMessage('User updated.', { classes: 'rw-flash-success' })
},
})
@@ -45,11 +45,13 @@ export const Success = ({ user }) => {
updateUser({ variables: { userName, input } })
}
- return
+ return (
+
+ )
}
diff --git a/web/src/components/EmojiReaction/EmojiReaction.js b/web/src/components/EmojiReaction/EmojiReaction.js
index f4dd910..ce254b9 100644
--- a/web/src/components/EmojiReaction/EmojiReaction.js
+++ b/web/src/components/EmojiReaction/EmojiReaction.js
@@ -1,5 +1,5 @@
import { useState } from 'react'
-import { getActiveClasses } from "get-active-classes"
+import { getActiveClasses } from 'get-active-classes'
import Popover from '@material-ui/core/Popover'
import { useAuth } from '@redwoodjs/auth'
@@ -7,14 +7,21 @@ import Svg from 'src/components/Svg'
const emojiMenu = ['❤️', '👍', '😄', '🙌']
// const emojiMenu = ['🏆', '❤️', '👍', '😊', '😄', '🚀', '👏', '🙌']
-const noEmotes =[{
- emoji: '❤️',
- count: 0,
-}]
+const noEmotes = [
+ {
+ emoji: '❤️',
+ count: 0,
+ },
+]
-const textShadow = {textShadow: '0 4px 6px rgba(0, 0, 0, 0.3)'}
+const textShadow = { textShadow: '0 4px 6px rgba(0, 0, 0, 0.3)' }
-const EmojiReaction = ({ emotes, userEmotes, onEmote = () => {}, className }) => {
+const EmojiReaction = ({
+ emotes,
+ userEmotes,
+ onEmote = () => {},
+ className,
+}) => {
const { currentUser } = useAuth()
const [isOpen, setIsOpen] = useState(false)
const [anchorEl, setAnchorEl] = useState(null)
@@ -48,29 +55,40 @@ const EmojiReaction = ({ emotes, userEmotes, onEmote = () => {}, className }) =>
return (
<>
-
-
-
-
-
-
-
+
+
{(emotes.length ? emotes : noEmotes).map((emote, i) => (
handleEmojiClick(emote.emoji)}
>
- {emote.emoji} {emote.count}
+ {emote.emoji}
+ {emote.count}
))}
@@ -96,7 +114,9 @@ const EmojiReaction = ({ emotes, userEmotes, onEmote = () => {}, className }) =>
style={textShadow}
key={`${emoji}-${i}}`}
onClick={() => handleEmojiClick(emoji)}
- >{emoji}
+ >
+ {emoji}
+
))}
diff --git a/web/src/components/IdePartCell/IdePartCell.js b/web/src/components/IdePartCell/IdePartCell.js
index 122ed88..703f70b 100644
--- a/web/src/components/IdePartCell/IdePartCell.js
+++ b/web/src/components/IdePartCell/IdePartCell.js
@@ -35,8 +35,7 @@ export const Success = ({ part }) => {
addMessage('Part updated.', { classes: 'rw-flash-success' })
},
})
- console.log({updatePart})
-
+ console.log({ updatePart })
const saveCode = (input, id) => {
console.log(id, input, 'wowow')
diff --git a/web/src/components/ImageUploader/ImageUploader.js b/web/src/components/ImageUploader/ImageUploader.js
index ca93f5e..3534293 100644
--- a/web/src/components/ImageUploader/ImageUploader.js
+++ b/web/src/components/ImageUploader/ImageUploader.js
@@ -1,6 +1,6 @@
-import React, { useCallback, useState } from "react";
-import { useDropzone } from "react-dropzone";
-import Button from "@material-ui/core/Button";
+import React, { useCallback, useState } from 'react'
+import { useDropzone } from 'react-dropzone'
+import Button from '@material-ui/core/Button'
import axios from 'axios'
import ReactCrop from 'react-image-crop'
import { Dialog } from '@material-ui/core'
@@ -8,17 +8,17 @@ import { Image as CloudinaryImage } from 'cloudinary-react'
import 'react-image-crop/dist/ReactCrop.css'
import Svg from 'src/components/Svg/Svg.js'
-const CLOUDINARY_UPLOAD_PRESET = "CadHub_project_images";
-const CLOUDINARY_UPLOAD_URL = "https://api.cloudinary.com/v1_1/irevdev/upload";
+const CLOUDINARY_UPLOAD_PRESET = 'CadHub_project_images'
+const CLOUDINARY_UPLOAD_URL = 'https://api.cloudinary.com/v1_1/irevdev/upload'
export default function ImageUploader({
- onImageUpload,
- imageUrl,
- aspectRatio,
- className,
- isEditable,
- width=600
- }) {
+ onImageUpload,
+ imageUrl,
+ aspectRatio,
+ className,
+ isEditable,
+ width = 600,
+}) {
const [isModalOpen, setIsModalOpen] = useState(false)
const [file, setFile] = useState()
const [cloudinaryId, setCloudinaryId] = useState(imageUrl)
@@ -27,17 +27,17 @@ export default function ImageUploader({
aspect: aspectRatio,
unit: '%',
width: 100,
- });
+ })
async function handleImageUpload() {
const croppedFile = await getCroppedImg(imageObj, crop, 'avatar')
- const imageData = new FormData();
- imageData.append('upload_preset', CLOUDINARY_UPLOAD_PRESET);
- imageData.append('file', croppedFile);
+ const imageData = new FormData()
+ imageData.append('upload_preset', CLOUDINARY_UPLOAD_PRESET)
+ imageData.append('file', croppedFile)
let upload = axios.post(CLOUDINARY_UPLOAD_URL, imageData)
try {
const { data } = await upload
- if (data && data.public_id !== "") {
- onImageUpload({cloudinaryPublicId: data.public_id})
+ if (data && data.public_id !== '') {
+ onImageUpload({ cloudinaryPublicId: data.public_id })
setCloudinaryId(data.public_id)
setIsModalOpen(false)
}
@@ -46,62 +46,85 @@ export default function ImageUploader({
}
}
// Drag and Drop
- const onDrop = useCallback(acceptedFiles => {
+ const onDrop = useCallback((acceptedFiles) => {
setIsModalOpen(true)
const fileReader = new FileReader()
fileReader.onload = () => {
setFile(fileReader.result)
}
fileReader.readAsDataURL(acceptedFiles[0])
- }, []);
+ }, [])
- const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });
+ const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop })
return (
-
+
- {cloudinaryId && isEditable &&
-
- }
+ {cloudinaryId && isEditable && (
+
+
+
+ )}
{isEditable &&
}
- {(cloudinaryId || !isEditable) &&
-
-
}
- {!cloudinaryId &&
}
- {!cloudinaryId && isEditable &&
-
- Drop files here ...
- or
- upload
-
+ {(cloudinaryId || !isEditable) && (
+
+
-
}
+ )}
+ {!cloudinaryId &&
}
+ {!cloudinaryId && isEditable && (
+
+
+ Drop files here ... or{' '}
+
+
+ upload
+
+
+
+
+ )}
-
setIsModalOpen(false)}
- >
+ setIsModalOpen(false)}>
- setImageObj(image)} onChange={newCrop => setCrop(newCrop)} />
- Upload
+ setImageObj(image)}
+ onChange={(newCrop) => setCrop(newCrop)}
+ />
+
+ Upload
+
- );
+ )
}
function getCroppedImg(image, crop, fileName) {
- const canvas = document.createElement('canvas');
- const scaleX = image.naturalWidth / image.width;
- const scaleY = image.naturalHeight / image.height;
- canvas.width = crop.width;
- canvas.height = crop.height;
- const ctx = canvas.getContext('2d');
+ const canvas = document.createElement('canvas')
+ const scaleX = image.naturalWidth / image.width
+ const scaleY = image.naturalHeight / image.height
+ canvas.width = crop.width
+ canvas.height = crop.height
+ const ctx = canvas.getContext('2d')
ctx.drawImage(
image,
crop.x * scaleX,
@@ -112,16 +135,20 @@ function getCroppedImg(image, crop, fileName) {
0,
crop.width,
crop.height
- );
+ )
// As Base64 string
// const base64Image = canvas.toDataURL('image/jpeg');
// As a blob
return new Promise((resolve, reject) => {
- canvas.toBlob(blob => {
- blob.name = fileName;
- resolve(blob);
- }, 'image/jpeg', 1);
- });
+ canvas.toBlob(
+ (blob) => {
+ blob.name = fileName
+ resolve(blob)
+ },
+ 'image/jpeg',
+ 1
+ )
+ })
}
diff --git a/web/src/components/ImageUploader/ImageUploader.stories.js b/web/src/components/ImageUploader/ImageUploader.stories.js
index f5b9f65..e2a49bc 100644
--- a/web/src/components/ImageUploader/ImageUploader.stories.js
+++ b/web/src/components/ImageUploader/ImageUploader.stories.js
@@ -4,35 +4,39 @@ export const generated = () => {
return (
<>
AspectRatio:1, no initial image, editable
- <
- ImageUploader
- onImageUpload={({cloudinaryPublicId}) => console.log(cloudinaryPublicId)}
+
+ console.log(cloudinaryPublicId)
+ }
aspectRatio={1}
isEditable={true}
- className={"bg-red-400 rounded-half rounded-br-xl"}
+ className={'bg-red-400 rounded-half rounded-br-xl'}
/>
AspectRatio 16:9, no initial image, editable
- <
- ImageUploader
- onImageUpload={({cloudinaryPublicId}) => console.log(cloudinaryPublicId)}
- aspectRatio={16/9}
+
+ console.log(cloudinaryPublicId)
+ }
+ aspectRatio={16 / 9}
isEditable={true}
- className={"bg-red-400 rounded-xl"}
+ className={'bg-red-400 rounded-xl'}
imageUrl="CadHub/inakek2urbreynblzhgt"
/>
AspectRatio:1, no initial image, NOT editable
- <
- ImageUploader
- onImageUpload={({cloudinaryPublicId}) => console.log(cloudinaryPublicId)}
+
+ console.log(cloudinaryPublicId)
+ }
aspectRatio={1}
- className={"rounded-half rounded-br-xl"}
+ className={'rounded-half rounded-br-xl'}
/>
AspectRatio ,16:9 no initial image, NOT editable
- <
- ImageUploader
- onImageUpload={({cloudinaryPublicId}) => console.log(cloudinaryPublicId)}
- aspectRatio={16/9}
- className={"rounded-xl"}
+
+ console.log(cloudinaryPublicId)
+ }
+ aspectRatio={16 / 9}
+ className={'rounded-xl'}
imageUrl="CadHub/inakek2urbreynblzhgt"
/>
>
diff --git a/web/src/components/InputText/InputText.js b/web/src/components/InputText/InputText.js
index 93826dd..aad823b 100644
--- a/web/src/components/InputText/InputText.js
+++ b/web/src/components/InputText/InputText.js
@@ -1,9 +1,15 @@
import { getActiveClasses } from 'get-active-classes'
-const InputText = ({value, isEditable, onChange ,className}) => {
+const InputText = ({ value, isEditable, onChange, className }) => {
return (
<>
-
+
-
{value}
+
+ {value}
+
>
)
}
diff --git a/web/src/components/Part2Cell/Part2Cell.js b/web/src/components/Part2Cell/Part2Cell.js
index a9016c4..ecfc449 100644
--- a/web/src/components/Part2Cell/Part2Cell.js
+++ b/web/src/components/Part2Cell/Part2Cell.js
@@ -5,7 +5,11 @@ import { useAuth } from '@redwoodjs/auth'
import PartProfile from 'src/components/PartProfile'
export const QUERY = gql`
- query FIND_PART_BY_USERNAME_TITLE($userName: String!, $partTitle: String, $currentUserId: String) {
+ query FIND_PART_BY_USERNAME_TITLE(
+ $userName: String!
+ $partTitle: String
+ $currentUserId: String
+ ) {
userPart: userName(userName: $userName) {
id
name
@@ -42,7 +46,7 @@ export const QUERY = gql`
const UPDATE_PART_MUTATION = gql`
mutation UpdatePartMutation($id: String!, $input: UpdatePartInput!) {
- updatePart:updatePart(id: $id, input: $input) {
+ updatePart: updatePart(id: $id, input: $input) {
id
title
user {
@@ -66,7 +70,7 @@ const CREATE_PART_MUTATION = gql`
`
const TOGGLE_REACTION_MUTATION = gql`
mutation ToggleReactionMutation($input: TogglePartReactionInput!) {
- togglePartReaction(input: $input){
+ togglePartReaction(input: $input) {
id
emote
}
@@ -87,23 +91,33 @@ export const Empty = () =>
Empty
export const Failure = ({ error }) =>
Error: {error.message}
-export const Success = ({ userPart, variables: {isEditable}, refetch}) => {
+export const Success = ({ userPart, variables: { isEditable }, refetch }) => {
const { currentUser } = useAuth()
const { addMessage } = useFlash()
const [updateUser, { loading, error }] = useMutation(UPDATE_PART_MUTATION, {
- onCompleted: ({updatePart}) => {
- navigate(routes.part2({userName: updatePart.user.userName, partTitle: updatePart.title}))
+ onCompleted: ({ updatePart }) => {
+ navigate(
+ routes.part2({
+ userName: updatePart.user.userName,
+ partTitle: updatePart.title,
+ })
+ )
addMessage('Part updated.', { classes: 'rw-flash-success' })
},
})
const [createUser] = useMutation(CREATE_PART_MUTATION, {
- onCompleted: ({createPart}) => {
- navigate(routes.part2({userName: createPart?.user?.userName, partTitle: createPart?.title}))
+ onCompleted: ({ createPart }) => {
+ navigate(
+ routes.part2({
+ userName: createPart?.user?.userName,
+ partTitle: createPart?.title,
+ })
+ )
addMessage('Part Created.', { classes: 'rw-flash-success' })
},
})
const onSave = (id, input) => {
- if(!id) {
+ if (!id) {
createUser({ variables: { input } })
return
}
@@ -111,30 +125,42 @@ export const Success = ({ userPart, variables: {isEditable}, refetch}) => {
}
const [toggleReaction] = useMutation(TOGGLE_REACTION_MUTATION, {
- onCompleted: () => refetch()
+ onCompleted: () => refetch(),
})
- const onReaction = (emote) => toggleReaction({variables: {input: {
- emote,
- userId: currentUser.sub,
- partId: userPart?.Part?.id,
- }}})
+ const onReaction = (emote) =>
+ toggleReaction({
+ variables: {
+ input: {
+ emote,
+ userId: currentUser.sub,
+ partId: userPart?.Part?.id,
+ },
+ },
+ })
const [createComment] = useMutation(CREATE_COMMENT_MUTATION, {
- onCompleted: () => refetch()
+ onCompleted: () => refetch(),
})
- const onComment = (text) => createComment({variables: {input: {
- text,
- userId: currentUser.sub,
- partId: userPart?.Part?.id,
- }}})
+ const onComment = (text) =>
+ createComment({
+ variables: {
+ input: {
+ text,
+ userId: currentUser.sub,
+ partId: userPart?.Part?.id,
+ },
+ },
+ })
- return
+ return (
+
+ )
}
diff --git a/web/src/components/PartProfile/PartProfile.js b/web/src/components/PartProfile/PartProfile.js
index 9a7facc..00beef0 100644
--- a/web/src/components/PartProfile/PartProfile.js
+++ b/web/src/components/PartProfile/PartProfile.js
@@ -1,58 +1,69 @@
-import {useState, useEffect} from 'react'
+import { useState, useEffect } from 'react'
import { useAuth } from '@redwoodjs/auth'
import { Link, navigate, routes } from '@redwoodjs/router'
-import Editor from "rich-markdown-editor";
+import Editor from 'rich-markdown-editor'
import ImageUploader from 'src/components/ImageUploader'
import Breadcrumb from 'src/components/Breadcrumb'
import EmojiReaction from 'src/components/EmojiReaction'
import Button from 'src/components/Button'
import { countEmotes } from 'src/helpers/emote'
-import { getActiveClasses } from 'get-active-classes';
+import { getActiveClasses } from 'get-active-classes'
const PartProfile = ({
- userPart,
- isEditable,
- onSave,
- loading,
- error,
- onReaction,
- onComment,
- }) => {
+ userPart,
+ isEditable,
+ onSave,
+ loading,
+ error,
+ onReaction,
+ onComment,
+}) => {
const [comment, setComment] = useState('')
const { currentUser } = useAuth()
const canEdit = currentUser?.sub === userPart.id
const part = userPart?.Part
const emotes = countEmotes(part?.Reaction)
- const userEmotes = part?.userReactions.map(({emote}) => emote)
- useEffect(() => {isEditable &&
- !canEdit &&
- navigate(routes.part2({userName: userPart.userName, partTitle: part.title}))},
- [currentUser])
+ const userEmotes = part?.userReactions.map(({ emote }) => emote)
+ useEffect(() => {
+ isEditable &&
+ !canEdit &&
+ navigate(
+ routes.part2({ userName: userPart.userName, partTitle: part.title })
+ )
+ }, [currentUser])
const [input, setInput] = useState({
title: part?.title,
mainImage: part?.mainImage,
description: part?.description,
userId: userPart?.id,
})
- const setProperty = (property, value) => setInput({
- ...input,
- [property]: value,
- })
- const onTitleChange = ({target}) => setProperty('title', target.value.replace(/([^a-zA-Z\d_:])/g, '-'))
- const onDescriptionChange = (description) => setProperty('description', description())
- const onImageUpload = ({cloudinaryPublicId}) => setProperty('mainImage', cloudinaryPublicId)
+ const setProperty = (property, value) =>
+ setInput({
+ ...input,
+ [property]: value,
+ })
+ const onTitleChange = ({ target }) =>
+ setProperty('title', target.value.replace(/([^a-zA-Z\d_:])/g, '-'))
+ const onDescriptionChange = (description) =>
+ setProperty('description', description())
+ const onImageUpload = ({ cloudinaryPublicId }) =>
+ setProperty('mainImage', cloudinaryPublicId)
const onEditSaveClick = () => {
if (isEditable) {
input.title && onSave(part?.id, input)
return
}
- navigate(routes.editPart2({userName: userPart.userName, partTitle: part.title}))
+ navigate(
+ routes.editPart2({ userName: userPart.userName, partTitle: part.title })
+ )
}
return (
<>
-
-
+
{/* Side column */}
- {userPart?.name}
+
+
+ {userPart?.name}
+
+
Open IDE
- {canEdit &&
- {isEditable ? 'Save Details' : 'Edit Details'}
- }
- {isEditable &&
}
+ {canEdit && (
+
+ {isEditable ? 'Save Details' : 'Edit Details'}
+
+ )}
+ {isEditable && (
+
+ )}
{/* main project center column */}
-
- { !!(input?.mainImage || isEditable) && }
-
+
+ {!!(input?.mainImage || isEditable) && (
+
+ )}
+
-
-
{/* comments */}
- { !isEditable && <>
-
-
Comments
+ {!isEditable && (
+ <>
+
+
+ Comments
+
-
- {part?.Comment.map(({text, user, id}) => (
-
-
-
{}}
- aspectRatio={1}
- imageUrl={user?.image}
- width={50}
+
+ {currentUser && (
+ <>
+
+
-
-
- {user.userName}
-
-
- {text}
-
-
-
- ))}
-
- {currentUser && <>
-
-
- onComment(comment)}
- >Comment
- >}
- >}
+ onComment(comment)}
+ >
+ Comment
+
+ >
+ )}
+ >
+ )}
-
>
)
diff --git a/web/src/components/Parts/Parts.js b/web/src/components/Parts/Parts.js
index 9547568..a661e57 100644
--- a/web/src/components/Parts/Parts.js
+++ b/web/src/components/Parts/Parts.js
@@ -4,14 +4,19 @@ import { countEmotes } from 'src/helpers/emote'
import ImageUploader from 'src/components/ImageUploader'
const PartsList = ({ parts }) => {
-
return (
-
- {parts.map(({title, mainImage, user, Reaction}) => (
-
+
+ {parts.map(({ title, mainImage, user, Reaction }) => (
+
@@ -23,7 +28,9 @@ const PartsList = ({ parts }) => {
width={50}
/>
-
{title}
+
+ {title}
+
{
imageUrl={mainImage}
width={700}
/>
-
+
- {countEmotes(Reaction).map(({emoji, count}) => (
-
-
- {emoji}
+
+ {countEmotes(Reaction).map(({ emoji, count }) => (
+
-
- {count}
-
-
- ))}
+ ))}
+
))}
diff --git a/web/src/components/ProfileTextInput/ProfileTextInput.js b/web/src/components/ProfileTextInput/ProfileTextInput.js
index e3d4bf6..d34b391 100644
--- a/web/src/components/ProfileTextInput/ProfileTextInput.js
+++ b/web/src/components/ProfileTextInput/ProfileTextInput.js
@@ -1,22 +1,30 @@
-import {Fragment} from 'react'
+import { Fragment } from 'react'
import InputText from 'src/components/InputText'
-const ProfileTextInput = ({fields, isEditable, onChange= () => {}}) => {
+const ProfileTextInput = ({ fields, isEditable, onChange = () => {} }) => {
return (
-
- {Object.entries(fields).map(([property, value]) => (
- {property}:
+
+ {Object.entries(fields).map(([property, value]) => (
+
+
+ {property}:
+
- onChange({...fields, [property]: target.value})}
- isEditable={isEditable}
- />
-
- ))}
+
+ onChange({ ...fields, [property]: target.value })
+ }
+ isEditable={isEditable}
+ />
+
+ ))}
)
diff --git a/web/src/components/Svg/Svg.js b/web/src/components/Svg/Svg.js
index d228c1d..a780be3 100644
--- a/web/src/components/Svg/Svg.js
+++ b/web/src/components/Svg/Svg.js
@@ -1,32 +1,113 @@
-const Svg = ({name, className: className2, strokeWidth = 2}) => {
-
+const Svg = ({ name, className: className2, strokeWidth = 2 }) => {
const svgs = {
- "chevron-down":
-
- ,
- "dots-vertical":
-
- ,
- "pencil":
-
- ,
- "plus":
-
- ,
- "plus-circle":
-
- ,
- "save":
-
- ,
- "terminal":
-
- ,
+ 'chevron-down': (
+
+
+
+ ),
+ 'dots-vertical': (
+
+
+
+ ),
+ pencil: (
+
+
+
+ ),
+ plus: (
+
+
+
+ ),
+ 'plus-circle': (
+
+
+
+ ),
+ save: (
+
+
+
+ ),
+ terminal: (
+
+
+
+ ),
}
- return
- {svgs[name]}
-
+ return
{svgs[name]}
}
export default Svg
diff --git a/web/src/components/User2Cell/User2Cell.js b/web/src/components/User2Cell/User2Cell.js
index e10d13c..bfdd7c4 100644
--- a/web/src/components/User2Cell/User2Cell.js
+++ b/web/src/components/User2Cell/User2Cell.js
@@ -18,6 +18,6 @@ export const Loading = () =>
Loading...
export const Empty = () =>
User not found
-export const Success = ({user}) => {
+export const Success = ({ user }) => {
return
}
diff --git a/web/src/components/UserProfile/UserProfile.js b/web/src/components/UserProfile/UserProfile.js
index 985e51c..f2b1dab 100644
--- a/web/src/components/UserProfile/UserProfile.js
+++ b/web/src/components/UserProfile/UserProfile.js
@@ -1,39 +1,41 @@
-import {useState, useEffect} from 'react'
+import { useState, useEffect } from 'react'
import { useAuth } from '@redwoodjs/auth'
import { navigate, routes } from '@redwoodjs/router'
-import Editor from "rich-markdown-editor";
+import Editor from 'rich-markdown-editor'
import ImageUploader from 'src/components/ImageUploader'
import Button from 'src/components/Button'
import ProfileTextInput from 'src/components/ProfileTextInput'
-
-const UserProfile = ({user, isEditable, loading, onSave, error}) => {
+const UserProfile = ({ user, isEditable, loading, onSave, error }) => {
const { currentUser } = useAuth()
const canEdit = currentUser?.sub === user.id
- useEffect(() => {isEditable &&
- !canEdit &&
- navigate(routes.user2({userName: user.userName}))},
- [currentUser])
+ useEffect(() => {
+ isEditable &&
+ !canEdit &&
+ navigate(routes.user2({ userName: user.userName }))
+ }, [currentUser])
const [input, setInput] = useState({
userName: user.userName,
name: user.name,
bio: user.bio,
image: user.image,
})
- const {userName, name} = input
- const editableTextFields = {userName, name}
+ const { userName, name } = input
+ const editableTextFields = { userName, name }
return (
<>
-
+
setInput({
- ...input,
- image,
- })}
+ onImageUpload={({ cloudinaryPublicId: image }) =>
+ setInput({
+ ...input,
+ image,
+ })
+ }
aspectRatio={1}
isEditable={isEditable}
imageUrl={user.image}
@@ -41,29 +43,53 @@ const UserProfile = ({user, isEditable, loading, onSave, error}) => {
/>
-
setInput({
- ...input,
- name,
- userName: userName.replace(/([^a-zA-Z\d_:])/g, '-'),
- })} isEditable={isEditable}/>
- {isEditable ?
- onSave(user.userName, input)}>Save Profile : // TODO replace pencil with a save icon
- canEdit ?
- navigate(routes.editUser2({userName: user.userName}))}>Edit Profile :
- null
- }
+
+ setInput({
+ ...input,
+ name,
+ userName: userName.replace(/([^a-zA-Z\d_:])/g, '-'),
+ })
+ }
+ isEditable={isEditable}
+ />
+ {isEditable ? (
+ onSave(user.userName, input)}
+ >
+ Save Profile
+ // TODO replace pencil with a save icon
+ ) : canEdit ? (
+
+ navigate(routes.editUser2({ userName: user.userName }))
+ }
+ >
+ Edit Profile
+
+ ) : null}
Bio:
-
+
setInput({
- ...input,
- bio: bioFn(),
- })}
+ onChange={(bioFn) =>
+ setInput({
+ ...input,
+ bio: bioFn(),
+ })
+ }
/>
diff --git a/web/src/helpers/emote.js b/web/src/helpers/emote.js
index 6f9cb95..2bb50b4 100644
--- a/web/src/helpers/emote.js
+++ b/web/src/helpers/emote.js
@@ -2,9 +2,12 @@ export const countEmotes = (reactions = []) => {
// would be good to do this sever side
// counting unique emojis, and limiting to the 5 largest
const emoteCounts = {}
- reactions.forEach(({emote}) => {
+ reactions.forEach(({ emote }) => {
emoteCounts[emote] = emoteCounts[emote] ? emoteCounts[emote] + 1 : 1
})
// TODO the sort is causing the emotes to jump around after the user clicks one, not ideal
- return Object.entries(emoteCounts).map(([emoji, count]) => ({emoji, count})).sort((a,b) => a.count-b.count).slice(-5)
+ return Object.entries(emoteCounts)
+ .map(([emoji, count]) => ({ emoji, count }))
+ .sort((a, b) => a.count - b.count)
+ .slice(-5)
}
diff --git a/web/src/layouts/MainLayout/MainLayout.js b/web/src/layouts/MainLayout/MainLayout.js
index 045609d..57d0db0 100644
--- a/web/src/layouts/MainLayout/MainLayout.js
+++ b/web/src/layouts/MainLayout/MainLayout.js
@@ -1,11 +1,11 @@
import { useState, useEffect } from 'react'
-import { Link, navigate ,routes } from '@redwoodjs/router'
+import { Link, navigate, routes } from '@redwoodjs/router'
import { useAuth } from '@redwoodjs/auth'
import { Flash } from '@redwoodjs/web'
-import Tooltip from '@material-ui/core/Tooltip';
+import Tooltip from '@material-ui/core/Tooltip'
import { useQuery } from '@redwoodjs/web'
import Popover from '@material-ui/core/Popover'
-import {getActiveClasses} from 'get-active-classes'
+import { getActiveClasses } from 'get-active-classes'
export const QUERY = gql`
query FIND_USER_BY_ID($id: String!) {
@@ -17,14 +17,15 @@ export const QUERY = gql`
}
}
`
-import avatar from 'src/assets/harold.jpg'
import Svg from 'src/components/Svg'
import ImageUploader from 'src/components/ImageUploader'
import logo from 'src/layouts/MainLayout/Logo_2.jpg'
-const MainLayout = ({ children}) => {
+const MainLayout = ({ children }) => {
const { logIn, logOut, isAuthenticated, currentUser } = useAuth()
- const {data, loading} = useQuery(QUERY, {variables: {id: currentUser?.sub}})
+ const { data, loading } = useQuery(QUERY, {
+ variables: { id: currentUser?.sub },
+ })
const [isOpen, setIsOpen] = useState(false)
const [anchorEl, setAnchorEl] = useState(null)
const [popoverId, setPopoverId] = useState(undefined)
@@ -55,38 +56,59 @@ const MainLayout = ({ children}) => {
-
+
-
+
{/* Because of how specific these styles are to this heading/logo and it doesn't need to be replicated else where as well as it's very precise with the placement of "pre-alpha" I think it's appropriate. */}
-
CadHub
-
pre-alpha
+
+ CadHub
+
+
+ pre-alpha
+
-
- {isAuthenticated && data?.user?.userName ?
-
+
+ {isAuthenticated && data?.user?.userName ? (
+
- :
+
+ ) : (
- }
+ )}
-
- {!loading &&
{}}
- aspectRatio={1}
- imageUrl={data?.user?.image}
- width={80}
- />}
+
+ {!loading && (
+ {}}
+ aspectRatio={1}
+ imageUrl={data?.user?.image}
+ width={80}
+ />
+ )}
@@ -104,23 +126,33 @@ const MainLayout = ({ children}) => {
horizontal: 'right',
}}
>
- {
- isAuthenticated && currentUser?
-
-
-
Hello {data?.user?.name}
-
-
-
-
-
Edit Profile
-
-
Logout
-
:
-
- }
+ {isAuthenticated && currentUser ? (
+
+
+
+ Hello {data?.user?.name}
+
+
+
+
+
+
Edit Profile
+
+
+ Logout
+
+
+ ) : (
+
+ )}
diff --git a/web/src/pages/EditPart2Page/EditPart2Page.js b/web/src/pages/EditPart2Page/EditPart2Page.js
index e98254c..808dafa 100644
--- a/web/src/pages/EditPart2Page/EditPart2Page.js
+++ b/web/src/pages/EditPart2Page/EditPart2Page.js
@@ -3,7 +3,7 @@ import { useAuth } from '@redwoodjs/auth'
import MainLayout from 'src/layouts/MainLayout'
import Part2Cell from 'src/components/Part2Cell'
-const EditPart2Page = ({userName, partTitle}) => {
+const EditPart2Page = ({ userName, partTitle }) => {
const { currentUser } = useAuth()
return (
diff --git a/web/src/pages/EditUser2Page/EditUser2Page.js b/web/src/pages/EditUser2Page/EditUser2Page.js
index 767effa..86c8d1a 100644
--- a/web/src/pages/EditUser2Page/EditUser2Page.js
+++ b/web/src/pages/EditUser2Page/EditUser2Page.js
@@ -4,7 +4,7 @@ import EditUser2Cell from 'src/components/EditUser2Cell'
const UserPage = ({ userName }) => {
return (
-
+
)
}
diff --git a/web/src/pages/HomePage/HomePage.js b/web/src/pages/HomePage/HomePage.js
index 8e247ce..ff000c9 100644
--- a/web/src/pages/HomePage/HomePage.js
+++ b/web/src/pages/HomePage/HomePage.js
@@ -3,8 +3,7 @@ import MainLayout from 'src/layouts/MainLayout'
import { initialize } from 'src/cascade/js/MainPage/CascadeMain'
import { useEffect, useState } from 'react'
-const starterCode =
-`// Welcome to Cascade Studio! Here are some useful functions:
+const starterCode = `// Welcome to Cascade Studio! Here are some useful functions:
// Translate(), Rotate(), Scale(), Union(), Difference(), Intersection()
// Box(), Sphere(), Cylinder(), Cone(), Text3D(), Polygon()
// Offset(), Extrude(), RotatedExtrude(), Revolve(), Pipe(), Loft(),
@@ -25,7 +24,7 @@ Translate([0, 0, 50], Difference(sphere, [cylinderX, cylinderY, cylinderZ]));
Translate([-100, 0, 100], Text3D("cadhub.xyz"));
// Don't forget to push imported or oc-defined shapes into sceneShapes to add them to the workspace!
-`;
+`
const HomePage1 = () => {
const [code, setCode] = useState(starterCode)
@@ -34,39 +33,83 @@ const HomePage1 = () => {
new initialize(sickCallback, starterCode)
}, [])
return (
-
current code {code}
-
+
@@ -74,11 +117,7 @@ const HomePage1 = () => {
}
const HomePage = () => {
- return (
-
- hi
-
- )
+ return hi
}
export default HomePage
diff --git a/web/src/pages/IdePartPage/IdePartPage.js b/web/src/pages/IdePartPage/IdePartPage.js
index 7b33264..f24ef32 100644
--- a/web/src/pages/IdePartPage/IdePartPage.js
+++ b/web/src/pages/IdePartPage/IdePartPage.js
@@ -2,7 +2,7 @@ import { Link, routes } from '@redwoodjs/router'
import MainLayout from 'src/layouts/MainLayout'
import IdePartCell from 'src/components/IdePartCell'
-const IdePartPage = ({id}) => {
+const IdePartPage = ({ id }) => {
return (
diff --git a/web/src/pages/NewPart2Page/NewPart2Page.js b/web/src/pages/NewPart2Page/NewPart2Page.js
index c1cb4e4..85a7bc0 100644
--- a/web/src/pages/NewPart2Page/NewPart2Page.js
+++ b/web/src/pages/NewPart2Page/NewPart2Page.js
@@ -5,12 +5,11 @@ import { navigate, routes } from '@redwoodjs/router'
import MainLayout from 'src/layouts/MainLayout'
import Part2Cell from 'src/components/Part2Cell'
-
-const NewPart2Page = ({userName}) => {
+const NewPart2Page = ({ userName }) => {
const { isAuthenticated, currentUser } = useAuth()
- useEffect(() => {!isAuthenticated &&
- navigate(routes.home())},
- [currentUser])
+ useEffect(() => {
+ !isAuthenticated && navigate(routes.home())
+ }, [currentUser])
return (
{
+const Part2Page = ({ userName, partTitle }) => {
const { currentUser } = useAuth()
return (