From 4eea8bf968325d641d8e6aed0d9ea417554e99a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B3=B5=EC=A0=95=EB=AF=BC?= <102538362+jeongmin59@users.noreply.github.com> Date: Mon, 15 Apr 2024 23:00:54 +0900 Subject: [PATCH] =?UTF-8?q?:sparkles:=20Feat:=20webpack=20proxy=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95,=20axiosConfig=20=EC=B6=94=EA=B0=80,=20api?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=20(#151)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintcache | 1 + package.json | 4 +- src/api/@types/@asConst.ts | 6 +++ src/api/@types/RetrospectiveTemplates.ts | 7 ++- src/api/@types/Retrospectives.ts | 24 ++++----- src/api/@types/Thumbnail.ts | 21 ++++++++ src/api/__mock__/retrospectiveTemplate.ts | 16 +++--- src/api/axiosConfig.tsx | 38 ++++++++++++++ src/api/imageApi/postImageToS3.tsx | 15 ++++++ src/api/imageApi/putUserThumbnail.tsx | 15 ++++++ src/api/retrospectivesApi/getTemplate.tsx | 14 ++++++ .../retrospectivesApi/postRetrospective.tsx | 15 ++++++ .../createRetro/CreateButtonBox.tsx | 22 ++++++-- .../createRetro/modal/CreateModal.tsx | 50 +++++++++++++++---- .../createRetro/modal/ImageUpload.tsx | 11 ++-- .../createRetro/modal/StartDateCalender.tsx | 39 +++++++-------- .../createRetro/modal/TemplateSelect.tsx | 40 +++++++++++++-- src/components/my/component/ImageUploader.tsx | 9 ++-- src/pages/MyPage.tsx | 23 ++++++++- webpack.config.js | 2 +- yarn.lock | 10 ++-- 21 files changed, 303 insertions(+), 79 deletions(-) create mode 100644 .eslintcache create mode 100644 src/api/@types/Thumbnail.ts create mode 100644 src/api/axiosConfig.tsx create mode 100644 src/api/imageApi/postImageToS3.tsx create mode 100644 src/api/imageApi/putUserThumbnail.tsx create mode 100644 src/api/retrospectivesApi/getTemplate.tsx create mode 100644 src/api/retrospectivesApi/postRetrospective.tsx diff --git a/.eslintcache b/.eslintcache new file mode 100644 index 0000000..43c2c9e --- /dev/null +++ b/.eslintcache @@ -0,0 +1 @@ +[{"/Users/jeongmingong/past-forward-frontend/webpack.config.js":"1"},{"size":1775,"mtime":1713187107202,"results":"2","hashOfConfig":"3"},{"filePath":"4","messages":"5","suppressedMessages":"6","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1el0hh9","/Users/jeongmingong/past-forward-frontend/webpack.config.js",[],[]] \ No newline at end of file diff --git a/package.json b/package.json index 776a76a..d5281b2 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@emotion/eslint-plugin": "^11.11.0", "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.0", + "@types/uuid": "^9.0.8", "@types/webpack-env": "^1.18.4", "aws-amplify": "^6.0.27", "axios": "^1.6.8", @@ -60,8 +61,9 @@ "styled-components": "^6.1.8", "styled-reset": "^4.5.2", "ts-node": "^10.9.2", + "uuid": "^9.0.1", "webpack-env": "^0.8.0", - "yarn": "^1.22.21", + "yarn": "^1.22.22", "yup": "^1.4.0" }, "devDependencies": { diff --git a/src/api/@types/@asConst.ts b/src/api/@types/@asConst.ts index fabf48a..ca209e2 100644 --- a/src/api/@types/@asConst.ts +++ b/src/api/@types/@asConst.ts @@ -9,6 +9,11 @@ export const Status = { COMPLETED: 'COMPLETED', } as const; +export const RetrospectiveType = { + TEAM: 'TEAM', + PERSONAL: 'PERSONAL', +}; + export const Template = { 1: 'Keep', 2: 'Ploblem', @@ -19,3 +24,4 @@ export const Template = { export type TStatus = typeof Status; export type TOrder = typeof Order; export type TTemplate = typeof Template; +export type TRetrospective = typeof RetrospectiveType; diff --git a/src/api/@types/RetrospectiveTemplates.ts b/src/api/@types/RetrospectiveTemplates.ts index 5872fba..ea6f289 100644 --- a/src/api/@types/RetrospectiveTemplates.ts +++ b/src/api/@types/RetrospectiveTemplates.ts @@ -1,7 +1,10 @@ export interface RetrospectivesTemplateResponse { code: number; - message: string; - data: [{ id: number; name: string }]; + message: string | null; + data: Array<{ + id: number; + name: string; + }>; } export interface retrospectivesTemplateClient { diff --git a/src/api/@types/Retrospectives.ts b/src/api/@types/Retrospectives.ts index e9372a9..f717af7 100644 --- a/src/api/@types/Retrospectives.ts +++ b/src/api/@types/Retrospectives.ts @@ -1,4 +1,4 @@ -import { TStatus } from './@asConst'; +import { TRetrospective, TStatus } from './@asConst'; // get export interface GetRetrospectiveRequest { @@ -22,7 +22,7 @@ export interface GetRetrospectiveData { //post export interface PostRetrospectivesRequest { title: string; - teamId: number; + type: keyof TRetrospective; userId: number; templateId: number; status: keyof TStatus; @@ -32,19 +32,13 @@ export interface PostRetrospectivesRequest { } export interface PostRetrospectivesResponse { - code: number; - message: string; - data: { - id: number; - title: string; - teamId: number; - userId: number; - templateId: number; - status: keyof TStatus; - thumbnail: string; - startDate: string; - description: string; - }; + id: number; + title: string; + userId: number; + templateId: number; + status: keyof TStatus; + thumbnail: string; + description: string; } //delete diff --git a/src/api/@types/Thumbnail.ts b/src/api/@types/Thumbnail.ts new file mode 100644 index 0000000..7f72931 --- /dev/null +++ b/src/api/@types/Thumbnail.ts @@ -0,0 +1,21 @@ +//post +export interface PostImageToS3Request { + filename: string; + method: string; +} + +export interface PostImageToS3Response { + filename: string; + preSignedUrl: string; +} + +// 유저 프로필 사진 +export interface PutThumbnailRequest { + thumbnail: string; +} + +export interface PutThumbnailResponse { + userId: number; + email: string; + thumbnail: string; +} diff --git a/src/api/__mock__/retrospectiveTemplate.ts b/src/api/__mock__/retrospectiveTemplate.ts index 3b3bbba..aa13607 100644 --- a/src/api/__mock__/retrospectiveTemplate.ts +++ b/src/api/__mock__/retrospectiveTemplate.ts @@ -1,7 +1,9 @@ -// export const mockRetrospectiveTemplate: RetrospectivesTemplateResponse[] = [ -// { id: 1, name: 'hee' }, -// { -// id: 2, -// name: 'jung', -// }, -// ]; +import { RetrospectivesTemplateResponse } from '../@types/RetrospectiveTemplates'; + +export const mockRetrospectiveTemplate: RetrospectivesTemplateResponse[] = [ + // { id: 1, name: 'hee' }, + // { + // id: 2, + // name: 'jung', + // }, +]; diff --git a/src/api/axiosConfig.tsx b/src/api/axiosConfig.tsx new file mode 100644 index 0000000..6fcc92a --- /dev/null +++ b/src/api/axiosConfig.tsx @@ -0,0 +1,38 @@ +import { fetchAuthSession } from 'aws-amplify/auth'; +import axios from 'axios'; + +// Axios 인스턴스 생성 +const axiosInstance = axios.create({ + baseURL: 'https://api.pastforward.link/', + headers: { + 'Content-Type': 'application/json;charset=UTF-8', + }, +}); + +// Axios 요청을 보내기 전에 실행 +axiosInstance.interceptors.request.use( + async config => { + try { + // 현재 세션에서 토큰 가져오기 + const { accessToken } = (await fetchAuthSession()).tokens || {}; + + // accessToken이 없으면 반환 + if (!accessToken) { + console.log('세션 토큰 없음'); + return config; + } + + // 헤더에 토큰 추가 + config.headers['Authorization'] = `Bearer ${accessToken}`; + return config; + } catch (err) { + console.error('에러', err); + return config; + } + }, + error => { + return Promise.reject(error); + }, +); + +export default axiosInstance; diff --git a/src/api/imageApi/postImageToS3.tsx b/src/api/imageApi/postImageToS3.tsx new file mode 100644 index 0000000..5c51c92 --- /dev/null +++ b/src/api/imageApi/postImageToS3.tsx @@ -0,0 +1,15 @@ +import axiosInstance from '../axiosConfig'; +import { PostImageToS3Request, PostImageToS3Response } from '@/api/@types/Thumbnail'; + +// post 요청 +const postImageToS3 = async (requestData: PostImageToS3Request): Promise => { + try { + const response = await axiosInstance.post('/s3/pre-signed-url', requestData); + console.log('사진 s3 업로드 성공', response.data); + return response.data; + } catch (error) { + throw new Error('실패'); + } +}; + +export default postImageToS3; diff --git a/src/api/imageApi/putUserThumbnail.tsx b/src/api/imageApi/putUserThumbnail.tsx new file mode 100644 index 0000000..bcbc5f1 --- /dev/null +++ b/src/api/imageApi/putUserThumbnail.tsx @@ -0,0 +1,15 @@ +import axiosInstance from '../axiosConfig'; +import { PutThumbnailRequest, PutThumbnailResponse } from '@/api/@types/Thumbnail'; + +// put 요청 +const putUserThumbnail = async (requestData: PutThumbnailRequest): Promise => { + try { + const response = await axiosInstance.put('/users/{userId}/thumbnail', requestData); + console.log('프로필 사진 등록 성공', response.data); + return response.data; + } catch (error) { + throw new Error('실패'); + } +}; + +export default putUserThumbnail; diff --git a/src/api/retrospectivesApi/getTemplate.tsx b/src/api/retrospectivesApi/getTemplate.tsx new file mode 100644 index 0000000..1b22049 --- /dev/null +++ b/src/api/retrospectivesApi/getTemplate.tsx @@ -0,0 +1,14 @@ +import axiosInstance from '../axiosConfig'; +import { RetrospectivesTemplateResponse } from '@/api/@types/RetrospectiveTemplates'; + +const getTemplate = async () => { + try { + const response = await axiosInstance.get('/retrospective-templates'); + console.log('템플릿 조회 성공', response.data); + return response.data.data; + } catch (error) { + throw new Error('템플릿 조회 실패'); + } +}; + +export default getTemplate; diff --git a/src/api/retrospectivesApi/postRetrospective.tsx b/src/api/retrospectivesApi/postRetrospective.tsx new file mode 100644 index 0000000..987542a --- /dev/null +++ b/src/api/retrospectivesApi/postRetrospective.tsx @@ -0,0 +1,15 @@ +import axiosInstance from '../axiosConfig'; +import { PostRetrospectivesRequest, PostRetrospectivesResponse } from '@/api/@types/Retrospectives'; + +// post 요청 +const postRetrospective = async (requestData: PostRetrospectivesRequest): Promise => { + try { + const response = await axiosInstance.post('/retrospectives', requestData); + console.log('회고 생성 성공', response.data); + return response.data; + } catch (error) { + throw new Error('회고 생성 실패'); + } +}; + +export default postRetrospective; diff --git a/src/components/createRetro/CreateButtonBox.tsx b/src/components/createRetro/CreateButtonBox.tsx index 7df32c2..466ade1 100644 --- a/src/components/createRetro/CreateButtonBox.tsx +++ b/src/components/createRetro/CreateButtonBox.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState } from 'react'; import { useDisclosure } from '@chakra-ui/react'; import PersonalRetroCreateButton from '@/components/createRetro/PersonalRetroCreateButton'; import TeamRetroCreateButton from '@/components/createRetro/TeamRetroCreateButton'; @@ -7,18 +7,32 @@ import * as S from '@/styles/createRetro/CreateButtonBox.style'; const CreateButtonBox: React.FC = () => { const { isOpen, onOpen, onClose } = useDisclosure(); + const [templateId, setTemplateId] = useState(null); + const [type, setType] = useState<'TEAM' | 'PERSONAL'>('TEAM'); + + const handleTeamButtonClick = () => { + setTemplateId(1); + setType('TEAM'); // TEAM으로 type 설정 + onOpen(); + }; + + const handlePersonalButtonClick = () => { + setTemplateId(2); + setType('PERSONAL'); // PERSONAL로 type 설정 + onOpen(); + }; return ( <> - + - + - + ); }; diff --git a/src/components/createRetro/modal/CreateModal.tsx b/src/components/createRetro/modal/CreateModal.tsx index 20f3bcf..599ab7c 100644 --- a/src/components/createRetro/modal/CreateModal.tsx +++ b/src/components/createRetro/modal/CreateModal.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { Modal, @@ -9,9 +9,10 @@ import { ModalCloseButton, Button, } from '@chakra-ui/react'; -import { Status } from '@/api/@types/@asConst'; +import { Status, TRetrospective } from '@/api/@types/@asConst'; import { PostRetrospectivesRequest } from '@/api/@types/Retrospectives'; -import { RetrospectiveService } from '@/api/services/Retrospectives'; +import postImageToS3 from '@/api/imageApi/postImageToS3'; +import postRetrospective from '@/api/retrospectivesApi/postRetrospective'; import DescriptionInput from '@/components/createRetro/modal/DescriptionInput'; import ImageUpload from '@/components/createRetro/modal/ImageUpload'; import StartDateCalendar from '@/components/createRetro/modal/StartDateCalender'; @@ -22,29 +23,49 @@ import * as S from '@/styles/createRetro/modal/CreateModal.style'; interface CreateModalProps { isOpen: boolean; onClose: () => void; + templateId: number | null; + type: keyof TRetrospective; } -const CreateModal: React.FC = ({ isOpen, onClose }) => { +const CreateModal: React.FC = ({ isOpen, onClose, templateId, type }) => { const size = 'xl'; const navigate = useNavigate(); const [requestData, setRequestData] = useState({ title: '', - teamId: 1, + type: type, userId: 1, - templateId: 0, + templateId: templateId || 1, status: Status.NOT_STARTED, thumbnail: '', startDate: '', description: '', }); + useEffect(() => { + setRequestData(prevData => ({ + ...prevData, + templateId: templateId || 1, // templateId가 변경될 때마다 업데이트 + type: type, + })); + }, [templateId, type]); + const handleCreateClick = async () => { try { - const response = await RetrospectiveService.create({ + // 회고 먼저 생성 + const retrospectiveResponse = await postRetrospective({ ...requestData, status: Status.NOT_STARTED, }); - console.log('생성', response); + + // 이미지를 S3에 업로드 + const imageResponse = await postImageToS3({ + filename: requestData.thumbnail, // imageUUID를 filename으로 설정 + method: 'PUT', + }); + + console.log('회고 생성 성공', retrospectiveResponse); + console.log('사진 S3 업로드 성공', imageResponse); + onClose(); navigate('/invite'); } catch (error) { @@ -52,6 +73,10 @@ const CreateModal: React.FC = ({ isOpen, onClose }) => { } }; + const handleTemplateChange = (selectedTemplateId: number) => { + setRequestData({ ...requestData, templateId: selectedTemplateId }); + }; + return ( @@ -61,12 +86,15 @@ const CreateModal: React.FC = ({ isOpen, onClose }) => { - setRequestData({ ...requestData, thumbnail })} /> + setRequestData({ ...requestData, thumbnail: imageUUID })} + /> setRequestData({ ...requestData, title })} /> - setRequestData({ ...requestData, templateId })} /> - setRequestData({ ...requestData, startDate })} /> + + + setRequestData({ ...requestData, startDate })} /> diff --git a/src/components/createRetro/modal/ImageUpload.tsx b/src/components/createRetro/modal/ImageUpload.tsx index 73d4c96..c9c4d5c 100644 --- a/src/components/createRetro/modal/ImageUpload.tsx +++ b/src/components/createRetro/modal/ImageUpload.tsx @@ -1,12 +1,14 @@ import React, { ChangeEvent, useState } from 'react'; import { Input, Box, Image, Button, Center } from '@chakra-ui/react'; +import { v4 as uuidv4 } from 'uuid'; interface ImageUploadProps { - onChange: (image: string) => void; // 이미지 파일의 URL을 외부로 전달하는 함수 + onChange: (image: string, uuid: string) => void; // 이미지 파일의 URL, uuid를 외부로 전달하는 함수 } const ImageUpload: React.FC = ({ onChange }) => { const [imagePreview, setImagePreview] = useState(null); + const [, setImageUUID] = useState(null); const handleImageChange = (event: ChangeEvent) => { const file = event.target.files?.[0]; @@ -14,8 +16,11 @@ const ImageUpload: React.FC = ({ onChange }) => { const reader = new FileReader(); reader.onloadend = () => { const result = reader.result as string; + const uuid = uuidv4(); // UUID 생성 + setImageUUID(uuid); // 생성된 UUID 설정 setImagePreview(result); // 이미지 미리보기 업데이트 - onChange(result); // 외부로 이미지 URL 전달 + onChange(result, uuid); + console.log(uuid); }; reader.readAsDataURL(file); } @@ -24,9 +29,9 @@ const ImageUpload: React.FC = ({ onChange }) => { // 이미지 제거 함수 const handleRemoveImage = () => { setImagePreview(null); + setImageUUID(null); }; - // 이미지 업로드를 위한 input 컴포넌트 렌더링 return ( <> diff --git a/src/components/createRetro/modal/StartDateCalender.tsx b/src/components/createRetro/modal/StartDateCalender.tsx index 42df8ba..76e482a 100644 --- a/src/components/createRetro/modal/StartDateCalender.tsx +++ b/src/components/createRetro/modal/StartDateCalender.tsx @@ -1,33 +1,30 @@ -import { useState } from 'react'; -import 'react-datepicker/dist/react-datepicker.css'; +import React, { useState } from 'react'; import { ko } from 'date-fns/locale/ko'; +import 'react-datepicker/dist/react-datepicker.css'; import * as S from '@/styles/createRetro/modal/StartDateCalendar.style'; import '@/styles/createRetro/modal/Calendar.css'; -const StartDateCalendar: React.FC<{ onChange: (startedDate: string) => void }> = ({ onChange }) => { - const [selectedDate, setSelectedDate] = useState(null); +interface StartDateCalendarProps { + onDateChange: (dateString: string) => void; +} - const handleDateChange = (date: Date | null) => { - setSelectedDate(date); - onChange(date ? date.toISOString() : ''); // ISO 8601 형식으로 변환 - }; +const StartDateCalendar: React.FC = ({ onDateChange }) => { + const [selectedDate, setSelectedDate] = useState(new Date()); - const formatDateForDisplay = (date: Date | null) => { - return date ? date.toLocaleDateString('ko-KR') : ''; // 화면에 보여질 형식은 지역화된 날짜 형식을 사용합니다. + const handleDateChange = (date: Date) => { + setSelectedDate(date); + const isoDateString = date.toISOString(); // 백엔드 request body에 보낼 날짜 타입 + onDateChange(isoDateString); }; return ( - <> -
Start Date
- - + ); }; diff --git a/src/components/createRetro/modal/TemplateSelect.tsx b/src/components/createRetro/modal/TemplateSelect.tsx index 9520999..4f9d333 100644 --- a/src/components/createRetro/modal/TemplateSelect.tsx +++ b/src/components/createRetro/modal/TemplateSelect.tsx @@ -1,13 +1,43 @@ -import React from 'react'; +import React, { useState, useEffect } from 'react'; import { Select } from '@chakra-ui/react'; +import { RetrospectivesTemplateResponse } from '@/api/@types/RetrospectiveTemplates'; +import getTemplate from '@/api/retrospectivesApi/getTemplate'; + +interface TemplateSelectProps { + onChange: (templateId: number) => void; + defaultTemplateId: number | null; +} + +const TemplateSelect: React.FC = ({ onChange, defaultTemplateId }) => { + const [templates, setTemplates] = useState([]); + + useEffect(() => { + const fetchTemplates = async () => { + try { + const response = await getTemplate(); + console.log('템플릿 데이터', response); + setTemplates(response); + } catch (error) { + console.error('에러', error); + } + }; + + fetchTemplates(); + }, []); -const TemplateSelect: React.FC<{ onChange: (templateId: number) => void }> = ({ onChange }) => { return ( <>
Template
- onChange(Number(e.target.value))} + defaultValue={defaultTemplateId !== null ? defaultTemplateId.toString() : '1'} + > + {templates.map(template => ( + + ))} ); diff --git a/src/components/my/component/ImageUploader.tsx b/src/components/my/component/ImageUploader.tsx index b2ac2a9..5e2b173 100644 --- a/src/components/my/component/ImageUploader.tsx +++ b/src/components/my/component/ImageUploader.tsx @@ -1,11 +1,12 @@ import { ChangeEventHandler, FC, MouseEventHandler, useRef } from 'react'; import { PersonCircle } from 'react-bootstrap-icons'; import styled from 'styled-components'; +import { v4 as uuidv4 } from 'uuid'; import * as S from '@/styles/my/myPage.style'; interface Props { image: string; - setImage: (image: string) => void; + setImage: (image: string, uuid: string) => void; } const ImageUploader: FC = ({ image, setImage }) => { @@ -26,12 +27,14 @@ const ImageUploader: FC = ({ image, setImage }) => { const file = files[0]; const imageUrl = URL.createObjectURL(file); const imageUrlString: string = imageUrl; - setImage(imageUrlString); + const uuid = uuidv4(); + + setImage(imageUrlString, uuid); } }; const DeleteImage: MouseEventHandler = () => { - setImage(''); + setImage('', ''); }; return ( diff --git a/src/pages/MyPage.tsx b/src/pages/MyPage.tsx index ae7bd7f..8128321 100644 --- a/src/pages/MyPage.tsx +++ b/src/pages/MyPage.tsx @@ -1,4 +1,6 @@ import { useState } from 'react'; +import postImageToS3 from '@/api/imageApi/postImageToS3'; +import putUserThumbnail from '@/api/imageApi/putUserThumbnail'; import DeleteAccountButton from '@/components/my/DeleteAccountBox'; import EmailBox from '@/components/my/EmailBox'; import NicknameBox from '@/components/my/NicknameBox'; @@ -9,6 +11,25 @@ import * as S from '@/styles/my/myPage.style'; const MyPage = () => { const [image, setImage] = useState(''); + const handleSave = async () => { + try { + const s3Response = await postImageToS3({ + filename: image, + method: 'PUT', + }); + + const profileResponse = await putUserThumbnail({ + thumbnail: image, + }); + + console.log('사진 S3 업로드 성공', s3Response); + console.log('프로필 사진 등록 성공', profileResponse); + alert('변경 되었습니다.'); + } catch (error) { + console.error('실패', error); + } + }; + return ( <> @@ -26,7 +47,7 @@ const MyPage = () => { CANCEL - + SAVE diff --git a/webpack.config.js b/webpack.config.js index 69c69a8..9082b2d 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -22,7 +22,7 @@ module.exports = (env, argv) => { proxy: [ { context: ['/api'], - target: 'http://past-forward-load-balancer-1892345872.us-west-2.elb.amazonaws.com/', + target: 'https://api.pastforward.link/', }, ], }, diff --git a/yarn.lock b/yarn.lock index 57dc39e..c0deaf2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4049,7 +4049,7 @@ resolved "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.0.tgz" integrity sha512-n4sx2bqL0mW1tvDf/loQ+aMX7GQD3lc3fkCMC55VFNDu/vBOabO+LTIeXKM14xK0ppk5TUGcWRjiSpIlUpghKw== -"@types/uuid@^9.0.0": +"@types/uuid@^9.0.0", "@types/uuid@^9.0.8": version "9.0.8" resolved "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz" integrity sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA== @@ -11574,10 +11574,10 @@ yargs@~3.10.0: decamelize "^1.0.0" window-size "0.1.0" -yarn@^1.22.21: - version "1.22.21" - resolved "https://registry.npmjs.org/yarn/-/yarn-1.22.21.tgz" - integrity sha512-ynXaJsADJ9JiZ84zU25XkPGOvVMmZ5b7tmTSpKURYwgELdjucAOydqIOrOfTxVYcNXe91xvLZwcRh68SR3liCg== +yarn@^1.22.22: + version "1.22.22" + resolved "https://registry.yarnpkg.com/yarn/-/yarn-1.22.22.tgz#ac34549e6aa8e7ead463a7407e1c7390f61a6610" + integrity sha512-prL3kGtyG7o9Z9Sv8IPfBNrWTDmXB4Qbes8A9rEzt6wkJV8mUvoirjU0Mp3GGAU06Y0XQyA3/2/RQFVuK7MTfg== yn@3.1.1: version "3.1.1"