diff --git a/package.json b/package.json index ed588ce..2652c38 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "lint": "tslint './src/**/*.ts*' --format stylish --project . --force", "start": "yarn run start-dev", "start-dev": "webpack-dev-server --config=configs/webpack/dev.js", - "test": "jest --watch --coverage --config=configs/jest.config.js" + "test": "jest --watch --coverage --config=configs/jest.config.js", + "format": "prettier --write \"src/**/*.tsx\"" }, "devDependencies": { "@babel/cli": "^7.6.4", @@ -35,6 +36,7 @@ "jest-environment-enzyme": "^7.1.1", "jest-enzyme": "^7.1.1", "node-sass": "^4.13.1", + "prettier": "^3.0.3", "react": "^16.10.2", "react-dom": "^16.10.2", "rimraf": "^3.0.0", @@ -43,7 +45,9 @@ "style-loader": "^1.0.0", "terser-webpack-plugin": "^5.1.1", "ts-jest": "^26.5.4", - "tslint": "^5.20.0", + "tslint": "^6.1.3", + "tslint-config-prettier": "^1.18.0", + "tslint-plugin-prettier": "^2.3.0", "typescript": "4.5.4", "uglifyjs-webpack-plugin": "^2.2.0", "webpack": "^4.41.1", @@ -56,6 +60,7 @@ "@emotion/core": "^10.0.22", "@emotion/styled": "^10.0.22", "@hot-loader/react-dom": "16.10.2", + "axios": "^1.5.0", "react-hot-loader": "^4.12.15", "react-redux": "^7.1.1", "redux": "^4.0.4" diff --git a/src/components/App.tsx b/src/components/App.tsx index e8c7d74..2f3b361 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -1,21 +1,77 @@ -import React, { FC } from 'react' +import React, { FC, useState, useEffect } from 'react' import styled from '@emotion/styled' import Header from './Header' +import SearchBar from './SearchBar' +import GridItem from './GridItem' +import Favorites from './Favorites' +import { useSelector } from 'react-redux' const App: FC = () => { + const [breed, setBreed] = useState('terrier') + const [dogs, setDogs] = useState([]) + + // error handling hooks + const [dataComming, setDataComming] = useState(false) + + // redux call + const getdata = useSelector((state) => state.searchreducer.carts) + + // data updates a/c getData from search bar + useEffect(() => { + if (getdata.length > 0) { + const newBreed = getdata[0] // getdata is an array + fetchDogData(newBreed) + } else { + fetchDogData('affenpinscher') + } + }, [getdata]) + + const fetchDogData = async (currentBreed) => { + try { + const noOfData = 10 + const res = await fetch(`https://dog.ceo/api/breed/${currentBreed}/images/random/${noOfData}`) + const data = await res.json() + setDogs(data.message) + setDataComming(true) + } catch (error) { + setDataComming(false) + } + } + return ( - -
- {/* Happy coding! */} - + <> + {dataComming === true ? ( + +
+ + <> + + + + +
+ + ) : ( + +

Loading ...

+
+ )} + ) } const Container = styled.div({ + position: 'relative', + alignItems: 'center', margin: '0 auto', - height: '100%', - width: '560px', + height: '168%', + width: '681.73px', paddingTop: '60px', }) +const NoData = styled.div` + text-align: center; + margin-top: 50vh; +` + export default App diff --git a/src/components/Card.tsx b/src/components/Card.tsx new file mode 100644 index 0000000..ab971f9 --- /dev/null +++ b/src/components/Card.tsx @@ -0,0 +1,71 @@ +import React, { useState } from 'react' +import styled from '@emotion/styled' +import Heart from './Heart' +import { useDispatch } from 'react-redux' +import { ADD, DLT } from '../redux/actions' + +const Card = ({ prop1, prop2, index }) => { + const dispatch = useDispatch() + + // favorite prop1 or width size is 128px + let isTrue = false + if (prop1 === '128') { + isTrue = true + } + const [isFavorite, setIsFavorite] = useState(isTrue) + const send = (e) => { + dispatch(ADD(e)) + } + + const dlt = (id) => { + dispatch(DLT(id)) + } + + const toggleFavorite = () => { + // add toggle + if (isFavorite === false) { + send(prop2) + setIsFavorite(!isFavorite) + } + + // delete toggle + if (isFavorite) { + dlt(prop2) + setIsFavorite(!isFavorite) + } + } + return ( + +
+
+ +
+
+
+ ) +} + +export default Card + +const Griditem = styled.div` + .box { + background-color: rgba(255, 255, 255, 0.8); + height: ${(props) => props.prop1}px; + width: ${(props) => props.prop1}px; + border-radius: 5px; + border: none; + position: relative; + background-image: url('${(props) => props.prop2}'); + background-size: cover; + background-repeat: no-repeat; + .heartIcon { + position: absolute; + bottom: 0px; + right: 5px; + box-shadow: 0px 2px 2px 0px rgba(0, 0, 0, 0.25); + } + &:hover { + border: solid 1px #edf3f0; + } + } +` diff --git a/src/components/Favorites.tsx b/src/components/Favorites.tsx new file mode 100644 index 0000000..3f11813 --- /dev/null +++ b/src/components/Favorites.tsx @@ -0,0 +1,36 @@ +import React from 'react' +import styled from '@emotion/styled' +import Heart from './Heart' +import GridFavoriteItem from './GridFavoriteItem' + +const Favorites = () => { + return ( + + + + Favorites + + + + ) +} + +export default Favorites +const Container = styled.div` + width: 100%; + left: 62px; + position: absolute; + top: 1036px; +` +const Heading = styled.div` + display: flex; +` + +const Title = styled.div` + font-family: 'Nunito Sans', Arial, Helvetica, sans-serif; + font-weight: 700; + font-size: 24px; + line-height: 16px; + margin-left: 25.27px; + color: #000000; +` diff --git a/src/components/GridFavoriteItem.tsx b/src/components/GridFavoriteItem.tsx new file mode 100644 index 0000000..059fc96 --- /dev/null +++ b/src/components/GridFavoriteItem.tsx @@ -0,0 +1,42 @@ +import React from 'react' +import styled from '@emotion/styled' +import Card from './Card' +import { useSelector } from 'react-redux' + +// Favorite dog breeds data +const GridFavoriteItem = () => { + // Redux code + const getdata = useSelector((state) => state.favreducer.carts) + + // Create a Set to store unique images because there are duplicates + const uniqueURLs = new Set(getdata) + const uniqueData = Array.from(uniqueURLs) + + // height + const propValue1 = '128' + return ( + + + {uniqueData.map((imageURL, index) => ( + + ))} + + + ) +} + +export default GridFavoriteItem + +const Container = styled.div` + position: absolute; + width: 560px; + top: 56px; + margin-bottom: 50px; +` + +const GridContainer = styled.div` + display: grid; + grid-template-columns: auto auto auto auto; + column-gap: 20px; + row-gap: 20px; +` diff --git a/src/components/GridItem.tsx b/src/components/GridItem.tsx new file mode 100644 index 0000000..a47db39 --- /dev/null +++ b/src/components/GridItem.tsx @@ -0,0 +1,42 @@ +import React from 'react' +import styled from '@emotion/styled' +import Card from './Card' + +// general dog breeds images +const GridItem = ({ dogs }) => { + const propValue1 = '160' // height + const first10Images = dogs.slice(0, 10) + return ( + + + {first10Images.map((element, index) => ( + + ))} + +
+
+ ) +} + +export default GridItem + +const Container = styled.div` + position: absolute; + width: 560px; + left: 60px; + top: 196px; + + hr { + position: absolute; + top: 800px; + width: 560px; + border: solid 1px #dadada; + } +` + +const GridContainer = styled.div` + display: grid; + grid-template-columns: auto auto auto; + column-gap: 40px; + row-gap: 40px; +` diff --git a/src/components/Header.tsx b/src/components/Header.tsx index 275fbf8..fcb3902 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -6,20 +6,36 @@ const Header: FC = () => { return ( Dog Breeds - +
+ +
) } -const Container = styled.div({ - display: 'flex', - justifyContent: 'space-between', -}) +const Container = styled.div` + display: flex; + width: 560px; + justify-content: space-between; + position: absolute; + top: 57px; + left: 61px; + .icon { + margin-top: 8px; + } +` -const Title = styled.h1({ - fontWeight: 'bold', - fontSize: '24px', - lineHeight: '33px', -}) +const Title = styled.div` + position: relative; + font-family: 'Nunito Sans', sans-serif; + width: 131px; + height: 24px; + font-size: 24px; + font-weight: 700; + line-height: 33px; + letter-spacing: 0px; + text-align: left; + margin-bottom: 8px; +` export default Header diff --git a/src/components/Heart.tsx b/src/components/Heart.tsx index 2431e55..c93e422 100644 --- a/src/components/Heart.tsx +++ b/src/components/Heart.tsx @@ -8,13 +8,21 @@ interface Props { } const Heart: FC = ({ icon, alt }) => { - return + return ( + + + + ) } -const HeartIcon = styled.img({ - width: '17px', - height: '15px', - alignSelf: 'center', -}) +const Container = styled.div` + position: relative; + align-self: center; +` + +const HeartIcon = styled.img` + width: 16.73px; + height: 15px; +` export default Heart diff --git a/src/components/SearchBar.tsx b/src/components/SearchBar.tsx new file mode 100644 index 0000000..202716a --- /dev/null +++ b/src/components/SearchBar.tsx @@ -0,0 +1,119 @@ +import React, { useEffect, useState } from 'react' +import styled from '@emotion/styled' +import { icons } from '../assets' +import { SEARCH } from '../redux/actions' +import { useDispatch } from 'react-redux' + +const SearchBar = () => { + // redux call + const dispatch = useDispatch() + + // state hook for breed and search input + const [searchTerm, setSearchTerm] = useState(null) + const [suggestedBreeds, setSuggestedBreeds] = useState([]) + const [isData, setIsData] = useState(false) + + // breed list fetching + useEffect(() => { + const fetchDogData = async () => { + try { + const res = await fetch('https://dog.ceo/api/breeds/list/all') + const data = await res.json() + const breeds = Object.keys(data.message) + setSuggestedBreeds(breeds) + } catch (error) { + setIsData(true) + } + } + fetchDogData() + }, []) + + // Error handle if not fetch suggestion + if (isData) { + const data = ['affenpinscher', 'appenzeller', 'australian'] + setSuggestedBreeds(data) + } + const send = () => { + const breedValu = searchTerm + dispatch(SEARCH(breedValu)) + } + + return ( + + setSearchTerm(e.target.value)} + placeholder="Affenpinscher" + list="breed-suggestions" + /> + + + {suggestedBreeds.map((breed, index) => ( + + + + + ) +} + +export default SearchBar + +const Container = styled.div` + position: absolute; + width: 100%; + top: 121px; + left: 60px; + + input { + position: relative; + width: 560px; + height: 36px; + border-radius: 4px; + background-color: #f7f7f7; + border: none; + padding: 8px 262px 8px 17px; + font-family: 'Nunito Sans', sans-serif; + font-family: Nunito Sans; + font-size: 16px; + font-weight: 400; + line-height: 22px; + letter-spacing: 0px; + &:hover { + border: solid 2px #0794e3; + } + } + + button { + display: flex; + justify-content: space-evenly; + position: relative; + margin-top: -36px; + width: 105px; + height: 36px; + left: 455px; + border: none; + background-color: #0794e3; + color: #f7f7f7; + border-radius: 4px; + cursor: pointer; + } +` +const Title = styled.div` + margin-top: 9px; + line-height: 19.1px; + font-size: 14px; + text-align: center; + font-weight: 700; +` + +const SearchIcon = styled.img` + width: 20px; + height: 20px; + margin-top: 8px; +` diff --git a/src/redux/actions.ts b/src/redux/actions.ts index e69de29..a9bcb2e 100644 --- a/src/redux/actions.ts +++ b/src/redux/actions.ts @@ -0,0 +1,21 @@ +export const ADD = (item) => { + return { + type: 'ADD_CART', + payload: item, + } +} + +// remove items +export const DLT = (item) => { + return { + type: 'RMV_CART', + payload: item, + } +} + +export const SEARCH = (item) => { + return { + type: 'SEARCH_CART', + payload: item, + } +} diff --git a/src/redux/main.ts b/src/redux/main.ts new file mode 100644 index 0000000..00e85cd --- /dev/null +++ b/src/redux/main.ts @@ -0,0 +1,12 @@ +// if there is more diffrent type of reducers we can combine here + +import { combineReducers } from 'redux' +import { favreducer } from './reducer' +import { searchreducer } from './searchReducer' + +const rootred = combineReducers({ + favreducer, + searchreducer, +}) + +export default rootred diff --git a/src/redux/reducer.ts b/src/redux/reducer.ts index be51d22..273d0e8 100644 --- a/src/redux/reducer.ts +++ b/src/redux/reducer.ts @@ -1,6 +1,23 @@ -export const reducer = (initialState = {}, action) => { +const initialState = { + carts: [], +} + +export const favreducer = (state = initialState, action) => { switch (action.type) { + case 'ADD_CART': + return { + ...state, // spread operator to remain previous data add new data + carts: [...state.carts, action.payload], + } + + case 'RMV_CART': + const data = state.carts.filter((element) => element !== action.payload) + return { + ...state, + carts: data, + } + default: - return initialState + return state } } diff --git a/src/redux/searchReducer.ts b/src/redux/searchReducer.ts new file mode 100644 index 0000000..8b61811 --- /dev/null +++ b/src/redux/searchReducer.ts @@ -0,0 +1,15 @@ +const initialState = { + carts: [], +} + +export const searchreducer = (state = initialState, action) => { + switch (action.type) { + case 'SEARCH_CART': + return { + carts: [action.payload], + } + + default: + return state + } +} diff --git a/src/redux/store.ts b/src/redux/store.ts index 06536aa..580342c 100644 --- a/src/redux/store.ts +++ b/src/redux/store.ts @@ -1,4 +1,6 @@ import { createStore } from 'redux' -import { reducer } from './reducer' +import rootred from './main' -export default createStore(reducer) +const store = createStore(rootred) + +export default store diff --git a/src/reset.scss b/src/reset.scss index 5840053..ce0bfdd 100644 --- a/src/reset.scss +++ b/src/reset.scss @@ -1,7 +1,10 @@ + +@import url('https://fonts.googleapis.com/css2?family=Nunito+Sans:opsz,wght@6..12,700&display=swap'); html { min-height: 100vh; } + body { margin: 0; font-family: 'Nunito Sans', Arial, Helvetica, sans-serif; @@ -10,6 +13,7 @@ body { #root { height: 100%; + } * { diff --git a/yarn.lock b/yarn.lock index 2b88693..d284e5b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2105,6 +2105,15 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== +axios@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.5.0.tgz#f02e4af823e2e46a9768cfc74691fdd0517ea267" + integrity sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + babel-jest@^26.6.3: version "26.6.3" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" @@ -2980,7 +2989,7 @@ colorette@^1.2.2: resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== -combined-stream@^1.0.6, combined-stream@~1.0.6: +combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -4112,6 +4121,14 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" +eslint-plugin-prettier@^2.2.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.7.0.tgz#b4312dcf2c1d965379d7f9d5b5f8aaadc6a45904" + integrity sha512-CStQYJgALoQBw3FsBzH0VOVDRnJ/ZimUlpLm226U8qgqYJfPOY/CPK6wyRInMxh73HSKg5wyRwdS4BVYYHwokA== + dependencies: + fast-diff "^1.1.1" + jest-docblock "^21.0.0" + eslint-scope@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" @@ -4398,6 +4415,11 @@ fast-deep-equal@^3.1.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-diff@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" + integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== + fast-glob@^3.0.3: version "3.2.5" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661" @@ -4634,6 +4656,11 @@ follow-redirects@^1.0.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267" integrity sha512-DUgl6+HDzB0iEptNQEXLx/KhTmDb8tZUHSeLqpnjpknR70H0nC2t9N73BK6fN4hOvJ84pKlIQVQ4k5FFlBedKA== +follow-redirects@^1.15.0: + version "1.15.2" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + for-each@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" @@ -4651,6 +4678,15 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + form-data@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" @@ -6100,6 +6136,11 @@ jest-diff@^26.6.2: jest-get-type "^26.3.0" pretty-format "^26.6.2" +jest-docblock@^21.0.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" + integrity sha512-5IZ7sY9dBAYSV+YjQ0Ovb540Ku7AO9Z5o2Cg789xj167iQuZ2cG+z0f3Uct6WeYLbU6aQiM2pCs7sZ+4dotydw== + jest-docblock@^26.0.0: version "26.0.0" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" @@ -8240,6 +8281,11 @@ prepend-http@^2.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= +prettier@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.3.tgz#432a51f7ba422d1469096c0fdc28e235db8f9643" + integrity sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg== + pretty-error@^2.0.2: version "2.1.2" resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.2.tgz#be89f82d81b1c86ec8fdfbc385045882727f93b6" @@ -8322,6 +8368,11 @@ proxy-addr@~2.0.5: forwarded "~0.1.2" ipaddr.js "1.9.1" +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" @@ -10104,15 +10155,29 @@ ts-jest@^26.5.4: semver "7.x" yargs-parser "20.x" -tslib@^1.8.0, tslib@^1.8.1, tslib@^1.9.0: +tslib@^1.13.0, tslib@^1.7.1, tslib@^1.8.1, tslib@^1.9.0: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslint@^5.20.0: - version "5.20.1" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.20.1.tgz#e401e8aeda0152bc44dd07e614034f3f80c67b7d" - integrity sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg== +tslint-config-prettier@^1.18.0: + version "1.18.0" + resolved "https://registry.yarnpkg.com/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz#75f140bde947d35d8f0d238e0ebf809d64592c37" + integrity sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg== + +tslint-plugin-prettier@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/tslint-plugin-prettier/-/tslint-plugin-prettier-2.3.0.tgz#73fe71bf9f03842ac48c104122ca9b1de012ecf4" + integrity sha512-F9e4K03yc9xuvv+A0v1EmjcnDwpz8SpCD8HzqSDe0eyg34cBinwn9JjmnnRrNAs4HdleRQj7qijp+P/JTxt4vA== + dependencies: + eslint-plugin-prettier "^2.2.0" + lines-and-columns "^1.1.6" + tslib "^1.7.1" + +tslint@^6.1.3: + version "6.1.3" + resolved "https://registry.yarnpkg.com/tslint/-/tslint-6.1.3.tgz#5c23b2eccc32487d5523bd3a470e9aa31789d904" + integrity sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg== dependencies: "@babel/code-frame" "^7.0.0" builtin-modules "^1.1.1" @@ -10122,10 +10187,10 @@ tslint@^5.20.0: glob "^7.1.1" js-yaml "^3.13.1" minimatch "^3.0.4" - mkdirp "^0.5.1" + mkdirp "^0.5.3" resolve "^1.3.2" semver "^5.3.0" - tslib "^1.8.0" + tslib "^1.13.0" tsutils "^2.29.0" tsutils@^2.29.0: @@ -10214,10 +10279,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^3.6.4: - version "3.9.9" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.9.tgz#e69905c54bc0681d0518bd4d587cc6f2d0b1a674" - integrity sha512-kdMjTiekY+z/ubJCATUPlRDl39vXYiMV9iyeMuEuXZh2we6zz80uovNN2WlAxmmdE/Z/YQe+EbOEXB5RHEED3w== +typescript@4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.4.tgz#a17d3a0263bf5c8723b9c52f43c5084edf13c2e8" + integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg== uglify-js@3.4.x: version "3.4.10"