From b34e8b4e4431206cd62c1309d3f8f23e3e9ec534 Mon Sep 17 00:00:00 2001 From: soulsam480 Date: Thu, 23 Sep 2021 20:07:53 +0530 Subject: [PATCH] fix: organised settings, api response schema --- .vscode/settings.json | 4 +- api/src/controllers/cdn.ts | 5 +- api/src/services/cdn.ts | 3 +- .../User/pages/settings/ProfileSettings.tsx | 71 +++++++++++++------ app/src/User/services/users.ts | 5 +- app/src/utils/types.ts | 1 - 6 files changed, 59 insertions(+), 30 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 55712c1..25fa621 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "typescript.tsdk": "node_modules/typescript/lib" -} \ No newline at end of file + "typescript.tsdk": "node_modules/typescript/lib" +} diff --git a/api/src/controllers/cdn.ts b/api/src/controllers/cdn.ts index ec60789..6a9aa0f 100644 --- a/api/src/controllers/cdn.ts +++ b/api/src/controllers/cdn.ts @@ -2,7 +2,7 @@ import { GetObjectCommandInput, PutObjectCommandInput } from '@aws-sdk/client-s3 import { v4 as uuid } from 'uuid'; import { upload } from 'src/middlewares/multer'; import { getObject, getObjects, putObject } from 'src/services/cdn'; -import { normalize, parseEnv } from 'src/utils/helpers'; +import { formatResponse, normalize, parseEnv } from 'src/utils/helpers'; import { Router } from 'express'; import { auth } from 'src/middlewares/auth'; @@ -40,7 +40,7 @@ cdnRouter.post('/', upload, async (req, res) => { await putObject(objectParams); - return res.json({ key: file_name }); + return res.json(formatResponse({ key: file_name })); } catch (error) { console.log(error); @@ -48,7 +48,6 @@ cdnRouter.post('/', upload, async (req, res) => { } }); - //TODO: send file_name in query // e.g. http://localhost:3000/cdn/file?file_name=4df12050-a54f-46b7-99e0-42730d9d4127--June_logo.svg cdnRouter.get('/file', async (req, res) => { diff --git a/api/src/services/cdn.ts b/api/src/services/cdn.ts index 04054af..2495881 100644 --- a/api/src/services/cdn.ts +++ b/api/src/services/cdn.ts @@ -6,7 +6,6 @@ import { PutObjectCommandInput, } from '@aws-sdk/client-s3'; import { s3 } from 'src/db/s3'; -import { userModel } from 'src/entities/user'; import { parseEnv, streamToString } from 'src/utils/helpers'; const BUCKET = parseEnv('BUCKET_NAME'); @@ -48,4 +47,4 @@ export async function getObject(data: GetObjectCommandInput) { } catch (error) { Promise.reject(error); } -} \ No newline at end of file +} diff --git a/app/src/User/pages/settings/ProfileSettings.tsx b/app/src/User/pages/settings/ProfileSettings.tsx index 15a4a9a..7b9ab69 100644 --- a/app/src/User/pages/settings/ProfileSettings.tsx +++ b/app/src/User/pages/settings/ProfileSettings.tsx @@ -5,8 +5,8 @@ import JContainer from 'src/Lib/JContainer'; import JInput from 'src/Lib/JInput'; import { useUserStore } from 'src/User/store/useUserStore'; import { useAlert } from 'src/Lib/store/alerts'; -import { updateUserById, uploadImage } from '../../services/users'; -import { UpdateUserData, User } from 'src/utils/types'; +import { updateUserById, uploadImage } from 'src/User/services/users'; +import { UpdateUserData } from 'src/utils/types'; import { useNavigate } from 'react-router-dom'; import { useLoader } from 'src/Shared/store/loader'; import { diffMatcher } from 'src/utils/helpers'; @@ -21,7 +21,7 @@ const ProfileSettings: React.FC = () => { const navigate = useNavigate(); const inputFile = useRef(null); - const uploadFile = useRef(null); //React.RefObject + const uploadFile = useRef(null); const [userDetails, setUserDetails] = useState({ name: user.name, @@ -30,23 +30,55 @@ const ProfileSettings: React.FC = () => { image: user.image, username: user.username, }); + + function handleFileChange(e: React.ChangeEvent) { + if (e.target.files) { + uploadFile.current = e.target.files[0]; + } + } + + async function uploadProfileImage() { + if (!uploadFile.current) return; + + try { + const formData = new FormData(); + formData.append('file', uploadFile.current); + + const { + data: { + data: { key: image }, + }, + } = await uploadImage(formData); + + uploadFile.current = null; + + return image; + } catch (error) { + throw 'Unable to upload profile picture.'; + } + } + const updateUserDetails = async (e: FormEvent) => { e.preventDefault(); + let diffData = diffMatcher(user, userDetails); + try { setLoader(true); - if (uploadFile.current) { - const formData = new FormData(); - formData.append('file', uploadFile.current); - const imageKey = await uploadImage(formData); - diffData = { ...diffData, image: imageKey.data.key }; - } + + const image = await uploadProfileImage(); + + diffData = { ...diffData, image }; + if (!Object.keys(diffData).length) return; + const { data: { data: userFromResponse }, } = await updateUserById(user.id, diffData); + setUser({ ...userFromResponse }); setAlert({ type: 'success', message: 'Updated successfully' }); + navigate('/'); } catch (error) { setAlert({ type: 'danger', message: 'Unable to update user' }); @@ -84,19 +116,17 @@ const ProfileSettings: React.FC = () => { type="file" id="file" ref={inputFile} - style={{ display: 'none' }} - onChange={(e) => { - if (e.target.files) { - uploadFile.current = e.target.files[0]; - } - }} + className="hidden invisible" + multiple={false} + onChange={handleFileChange} /> + setUserDetails({ ...userDetails, name })} + onInput={(name) => setUserDetails((u) => ({ ...u, name }))} type="text" /> @@ -104,7 +134,7 @@ const ProfileSettings: React.FC = () => { label="username" id="username" value={userDetails.username} - onInput={(username) => setUserDetails({ ...userDetails, username })} + onInput={(username) => setUserDetails((u) => ({ ...u, username }))} type="text" /> @@ -113,15 +143,15 @@ const ProfileSettings: React.FC = () => { label="Email" id="email" value={userDetails.email} - onInput={(email) => setUserDetails({ ...userDetails, email })} - type="text" + onInput={(email) => setUserDetails((u) => ({ ...u, email }))} + type="email" /> setUserDetails({ ...userDetails, bio })} + onInput={(bio) => setUserDetails((u) => ({ ...u, bio }))} is="textarea" /> @@ -133,4 +163,5 @@ const ProfileSettings: React.FC = () => { ); }; + export default ProfileSettings; diff --git a/app/src/User/services/users.ts b/app/src/User/services/users.ts index a160a3d..d9c4090 100644 --- a/app/src/User/services/users.ts +++ b/app/src/User/services/users.ts @@ -31,10 +31,11 @@ export function getUserPostsById(id: string, opts: PaginationParams) { export function updateUserById(id: string, userData: UpdateUserData) { return api.patch>(`/users/${id}`, { ...userData }); } + export function updateUserPassword(id: string, passwords: UpdatePassword) { return api.post>(`/users/${id}/password`, { ...passwords }); } -export function uploadImage(file: any) { - return api.post>(`/cdn`, file); +export function uploadImage(file: FormData) { + return api.post>(`/cdn`, file); } diff --git a/app/src/utils/types.ts b/app/src/utils/types.ts index d890eb2..4a3e278 100644 --- a/app/src/utils/types.ts +++ b/app/src/utils/types.ts @@ -104,7 +104,6 @@ export interface Result { export type hookType = 'start' | 'cancel' | 'typing'; export interface ResponseSchema { - key: string | undefined; data: T; total_count?: number; has_more?: boolean;