Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • web-et-numerique/factory/llle_project/backoffice-client
1 result
Select Git revision
Show changes
Showing
with 472 additions and 126 deletions
import React, { useState } from 'react'
import React, { useContext } from 'react'
import { NavLink } from 'react-router-dom'
import routes from '../../constants/routes.json'
import burger from '../../assets/icons/menu.svg'
import logo from '../../assets/icons/ecolyo-logo.svg'
import login from '../../assets/icons/login.svg'
import editing from '../../assets/icons/editing.svg'
import settings from '../../assets/icons/settings.svg'
import './navbar.scss'
import { UserContext } from '../../hooks/userContext'
const Navbar: React.FC = () => {
const [isLogged] = useState<boolean>(false)
const { isLogged, logoutUser } = useContext(UserContext)
return (
<div className="navbar">
<img src={logo} alt="Ecolyo logo" className="logo" />
......@@ -24,10 +23,14 @@ const Navbar: React.FC = () => {
<img src={settings} className="navbar-icon" alt="Settings icon" />
Paramètres
</NavLink>
<NavLink to="/login" activeClassName="active">
<img src={login} className="navbar-icon" alt="Login icon" />
Login
</NavLink>
{isLogged ? (
<p onClick={logoutUser}>Logout</p>
) : (
<NavLink to="/login" activeClassName="active">
<img src={login} className="navbar-icon" alt="Login icon" />
Login
</NavLink>
)}
</div>
</div>
)
......
......@@ -10,6 +10,7 @@
align-items: center;
justify-content: center;
padding: 0 1rem;
z-index: 1500;
.menu-list {
display: flex;
align-items: center;
......
import { Editor } from '@tinymce/tinymce-react'
import React, { ChangeEvent } from 'react'
import { ContentItems } from '../Editing/Editing'
import './poll.scss'
interface PollProps {
question: string
link: string
handleChange: (
value: string,
type: 'header' | 'quote' | 'question' | 'link'
) => void
onSave: () => Promise<void>
onCancel: () => void
onDelete: (target: ContentItems) => void
}
const Poll: React.FC<PollProps> = ({
question,
link,
handleChange,
onSave,
onCancel,
onDelete,
}: PollProps) => {
const handleChangeLink = (e: ChangeEvent<HTMLInputElement>) => {
handleChange(e.target.value, 'link')
}
return (
<div className="poll">
<h2>Ajouter un sondage</h2>
<p className="title">Lien</p>
<input
type="text"
className="input-dark"
value={link}
onChange={handleChangeLink}
/>
<div>
<p className="title">Question</p>
<Editor
init={{
menubar: false,
toolbar:
'undo redo | bold italic underline | alignleft aligncenter alignright | code | ecolyoLink',
}}
value={question}
onEditorChange={(newQuestion, editor) =>
handleChange(newQuestion, 'question')
}
/>
<div className="buttons">
<button className="btnCancel" onClick={onCancel}>
Annuler
</button>
<button className="btnValid" onClick={onSave}>
Sauvegarder
</button>
<button className="btnDelete" onClick={() => onDelete('poll')}>
Supprimer
</button>
</div>
</div>
</div>
)
}
export default Poll
.poll {
margin: 2rem 0;
.title {
margin: 1rem 0;
}
input {
min-width: 300px;
margin-left: 0;
}
}
import React, { useContext } from 'react'
import { Route, Redirect } from 'react-router-dom'
import { UserContext } from '../../hooks/userContext'
interface PrivateRouteProps {
component: React.FC
path: string
exact: boolean
}
const PrivateRoute: React.FC<PrivateRouteProps> = ({
component,
path,
exact,
}: PrivateRouteProps) => {
const { isLogged } = useContext(UserContext)
return isLogged ? (
<Route path={path} exact={exact} component={component} />
) : (
<Redirect to="/login" />
)
}
export default PrivateRoute
import React from 'react'
import React, { useContext } from 'react'
import { Redirect, Route, Switch } from 'react-router-dom'
import { UserContext } from '../../hooks/userContext'
import Editing from '../Editing/Editing'
import Login from '../Login/Login'
import Settings from '../Settings/Settings'
import PrivateRoute from './PrivateRoute'
const Routes: React.FC = () => {
const { isLogged } = useContext(UserContext)
return (
<Switch>
<Route path="/editing" component={Editing} />
<Route path="/settings" component={Settings} />
{isLogged && <Redirect path="/login" to="/editing" />}
<Route path="/login" component={Login} />
<PrivateRoute path="/editing" component={Editing} exact />
<PrivateRoute path="/settings" component={Settings} exact />
<Redirect path="*" to="/editing" />
</Switch>
)
......
import React, { useState } from 'react'
import axios from 'axios'
import { User } from '../models/user.model'
const _apiUrl: string = 'https://localhost:1443/'
export interface Auth {
loginUser: () => Promise<void>
error: null
isUserLogged: () => Promise<boolean>
getUser: () => User | undefined
logoutUser: () => void
}
export const useAuth = (): Auth => {
const [error, setError] = useState(null)
//login user
const loginUser = async (): Promise<void> => {
try {
await axios.get(`${_apiUrl}OAuth2Login`)
const { data } = await axios.get(`${_apiUrl}api/common/WhoAmI`)
if (data) {
console.log('whomi', data)
localStorage.setItem('user', JSON.stringify(data))
}
} catch (e) {
setError(e)
}
}
const logoutUser = (): void => {
localStorage.removeItem('user')
}
const isUserLogged = async (): Promise<boolean> => {
const user = localStorage.getItem('user')
if (user) {
try {
const { data } = await axios.get(`${_apiUrl}api/common/WhoAmI`)
if (data) {
console.log(data)
return true
}
return false
} catch (e) {
setError(e)
return false
}
} else {
return false
}
}
const getUser = (): User | undefined => {
const user = localStorage.getItem('user')
if (user) return JSON.parse(user) as User
}
return { loginUser, error, isUserLogged, getUser, logoutUser }
}
import React, { createContext, Dispatch, SetStateAction } from 'react'
import { User } from '../models/user.model'
export interface UserContextProps {
loginUser: () => Promise<void>
error: null
isLogged: boolean
user: User
logoutUser: () => void
setisLogged: Dispatch<SetStateAction<boolean>>
}
export const UserContext = createContext<Partial<UserContextProps>>({})
export interface IMonthlyNews {
year: number
month: number
header: string
quote: string
}
export interface IPoll {
year: number
month: number
question: string
link: string
}
export interface User {
displayName: string
id: string
isAdmin: boolean
login: string
xsrftoken: string
}
export class EditorService {
/**
* Creates a quotation and header for selected month
* @param date
* @param header
* @param quote
*/
public sendQuotation = async (
date: Date,
header: string,
quote: string
): Promise<void> => {
try {
const response = await fetch(
'https://localhost:1443/api/admin/monthlyNews',
{
method: 'POST',
body: JSON.stringify({
month: date.getMonth(),
year: date.getFullYear(),
header: header,
quote: quote,
}),
}
)
if (response.status !== 201) {
throw new Error(
`Le post n'a pas pu être créé (code ${response.status})`
)
}
console.log('Le post a été créé avec succès')
} catch (e) {
console.log(e)
}
}
/**
* Gets a quotation and header for selected month
*/
public getQuotation = async (): Promise<any> => {
try {
const response = await fetch(
'https://localhost:1443/api/admin/monthlyNews',
{
method: 'GET',
}
)
if (response.status !== 201) {
throw new Error(
`Erreur lors de la récupération (code ${response.status})`
)
}
return response.json()
} catch (e) {
console.log(e)
}
}
}
import axios from 'axios'
import { IMonthlyNews } from '../models/monthlyNews.model'
import { IPoll } from '../models/poll.model'
import { toast } from 'react-toastify'
export class MonthlyNewsService {
private readonly _apiUrl: string
constructor() {
this._apiUrl = 'https://localhost:1443/'
}
/**
* Creates a quotation and header for selected month
* @param date
* @param header
* @param quote
*/
public createMonthlyReport = async (
date: Date,
header: string,
quote: string,
token: string
): Promise<void> => {
try {
await axios.put(
`${this._apiUrl}api/admin/monthlyNews`,
{
month: date.getMonth(),
year: date.getFullYear(),
header: header,
quote: quote,
},
{
headers: {
'XSRF-TOKEN': token,
},
}
)
toast.success('Monthly news succesfully saved !')
} catch (e) {
toast.error('Failed to create monthly news')
console.log(e)
}
}
/**
* Gets a quotation and header for selected month
*/
public getSingleMonthlyReport = async (
year: number,
month: number,
token: string
): Promise<IMonthlyNews | null> => {
try {
const { data } = await axios.get(
`${this._apiUrl}api/admin/monthlyNews/${year}/${month}`,
{
headers: {
'XSRF-TOKEN': token,
},
}
)
if (data == {}) {
return null
}
return data as IMonthlyNews
} catch (e) {
console.log('error', e)
return null
}
}
/**
* Gets a poll with question and link for selected month
*/
public getSinglePoll = async (
year: number,
month: number,
token: string
): Promise<IPoll | null> => {
try {
const { data } = await axios.get(
`${this._apiUrl}api/admin/poll/${year}/${month}`,
{
headers: {
'XSRF-TOKEN': token,
},
}
)
if (data === {}) {
return null
}
return data as IPoll
} catch (e) {
console.log('error', e)
return null
}
}
/**
* Creates a poll with question and link for selected month
* @param date
* @param question
* @param link
*/
public createPoll = async (
date: Date,
question: string,
link: string,
token: string
): Promise<void> => {
try {
await axios.put(
`${this._apiUrl}api/admin/poll`,
{
month: date.getMonth(),
year: date.getFullYear(),
link: link,
question: question,
},
{
headers: {
'XSRF-TOKEN': token,
},
}
)
toast.success('Poll successfully saved !')
} catch (e) {
toast.error('Failed to create poll')
console.log(e)
}
}
/**
* Deletes a poll for selected month
* @param month
* @param year
* @param token
*/
public deletePoll = async (
year: number,
month: number,
token: string
): Promise<void> => {
try {
await axios.delete(`${this._apiUrl}api/admin/poll/${year}/${month}`, {
headers: {
'XSRF-TOKEN': token,
},
})
toast.success('Poll succesfully deleted !')
} catch (e) {
toast.error('Failed to delete poll')
console.log(e)
}
}
/**
* Deletes a Monthly News for selected month
* @param year
* @param month
* @param token
*/
public deleteMonthlyNews = async (
year: number,
month: number,
token: string
): Promise<void> => {
try {
await axios.delete(
`${this._apiUrl}api/admin/monthlyNews/${year}/${month}`,
{
headers: {
'XSRF-TOKEN': token,
},
}
)
toast.success('Monthly news succesfully deleted !')
} catch (e) {
toast.error('Failed to delete monthly news')
console.log(e)
}
}
}
@import 'config/colors';
.Toastify__toast {
background: #fafafa !important;
}
.Toastify__toast--success {
.toastBody {
color: #73a839;
}
.toastProgress {
background: #73a839 !important;
}
}
.Toastify__toast--error {
.toastBody {
color: #c71c22;
}
.toastProgress {
background: #c71c22 !important;
}
}
.toastBody {
font-size: 1rem !important;
}
$menu-width: 8rem;
$navbar-height: 3.5rem;
$navigator-height: 8rem;
......@@ -59,3 +59,24 @@ $main-spacing: 4px;
background: darken($text-grey, 20%);
}
}
.btnDelete {
@include baseButton();
display: inline-block;
margin-left: auto;
background: $dark-light;
color: $gold;
border: 1px solid $gold;
&:hover {
background: $dark-light;
color: $text-grey;
border: 1px solid $text-grey;
}
}
.input-dark {
display: inline-block;
margin-left: 0.5rem;
background: transparent;
border: solid 1px $gold;
border-radius: 5px;
padding: 0.3rem;
}
......@@ -2,9 +2,8 @@
@import 'config/colors';
@import 'config/typography';
@import 'config/layout';
// To customize bulma variables, we set them before importing bulma
// @import 'bulma/bulma.sass';
@import 'config/layout';
@import 'toast';
* {
margin: 0;
......
......@@ -1473,11 +1473,6 @@
schema-utils "^2.6.5"
source-map "^0.7.3"
 
"@popperjs/core@^2.9.2":
version "2.9.2"
resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.9.2.tgz#adea7b6953cbb34651766b0548468e743c6a2353"
integrity sha512-VZMYa7+fXHdwIq1TDhSXoVmSPEGM/aa+6Aiq3nVVJ9bXr24zScr+NlKFKC3iPljA7ho/GAZr+d2jOf5GIRC30Q==
"@rollup/plugin-node-resolve@^7.1.1":
version "7.1.3"
resolved "https://registry.yarnpkg.com/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz#80de384edfbd7bfc9101164910f86078151a3eca"
......@@ -1675,7 +1670,7 @@
dependencies:
"@babel/runtime" "^7.12.5"
 
"@tinymce/tinymce-react@^3.12.6":
"@tinymce/tinymce-react@^3.3.1":
version "3.12.6"
resolved "https://registry.yarnpkg.com/@tinymce/tinymce-react/-/tinymce-react-3.12.6.tgz#8a4e2a5c5026b7a0c9c4c839af4d691804aa0604"
integrity sha512-a7/Ns7uVsSr2N0fCxn+OhDx8f9JqfywTlHbXsgcwlWB6vIBMIjjRBJ6PGo/5H0y2vfzO6fBzd4gc6h05Cm5R7A==
......@@ -2697,6 +2692,13 @@ axe-core@^4.0.2:
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.1.2.tgz#7cf783331320098bfbef620df3b3c770147bc224"
integrity sha512-V+Nq70NxKhYt89ArVcaNL9FDryB3vQOd+BFXZIfO3RP6rwtj+2yqqqdHEkacutglPaZLkJeuXKCjCJDMGPtPqg==
 
axios@^0.21.1:
version "0.21.1"
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8"
integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==
dependencies:
follow-redirects "^1.10.0"
axobject-query@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"
......@@ -3145,11 +3147,6 @@ builtin-status-codes@^3.0.0:
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=
 
bulma@^0.9.3:
version "0.9.3"
resolved "https://registry.yarnpkg.com/bulma/-/bulma-0.9.3.tgz#ddccb7436ebe3e21bf47afe01d3c43a296b70243"
integrity sha512-0d7GNW1PY4ud8TWxdNcP6Cc8Bu7MxcntD/RRLGWuiw/s0a9P+XlH/6QoOIrmbj6o8WWJzJYhytiu9nFjTszk1g==
bytes@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
......@@ -3438,11 +3435,6 @@ class-utils@^0.3.5:
isobject "^3.0.0"
static-extend "^0.1.1"
 
classnames@^2.2.6:
version "2.3.1"
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e"
integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==
clean-css@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78"
......@@ -3473,6 +3465,11 @@ cliui@^6.0.0:
strip-ansi "^6.0.0"
wrap-ansi "^6.2.0"
 
clsx@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188"
integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==
co@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
......@@ -5395,6 +5392,11 @@ follow-redirects@^1.0.0:
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.2.tgz#dd73c8effc12728ba5cf4259d760ea5fb83e3147"
integrity sha512-6mPTgLxYm3r6Bkkg0vNM0HTjfGrOEtsfbhagQvbxDEsEkpNhw582upBaoRZylzen6krEmxXJgt9Ju6HiI4O7BA==
 
follow-redirects@^1.10.0:
version "1.14.1"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.1.tgz#d9114ded0a1cfdd334e164e6662ad02bfd91ff43"
integrity sha512-HWqDgT7ZEkqRzBvc2s64vSZ/hfOceEol3ac/7tKwzuvEyWx3/4UegXh5oBOIotkGsObyk3xznnSRVADBgWSQVg==
for-in@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
......@@ -7445,7 +7447,7 @@ loglevel@^1.6.8:
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197"
integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw==
 
loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
......@@ -9515,18 +9517,6 @@ react-app-polyfill@^2.0.0:
regenerator-runtime "^0.13.7"
whatwg-fetch "^3.4.1"
 
react-datepicker@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/react-datepicker/-/react-datepicker-4.1.1.tgz#5ecef49c672b2250fca26327c988464e6ba52b62"
integrity sha512-vtZIA7MbUrffRw1CHiyOGtmTO/tTdZGr5BYaiRucHMTb6rCqA8TkaQhzX6tTwMwP8vV38Khv4UWohrJbiX1rMw==
dependencies:
"@popperjs/core" "^2.9.2"
classnames "^2.2.6"
date-fns "^2.0.1"
prop-types "^15.7.2"
react-onclickoutside "^6.10.0"
react-popper "^2.2.5"
react-dev-utils@^11.0.3:
version "11.0.4"
resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-11.0.4.tgz#a7ccb60257a1ca2e0efe7a83e38e6700d17aa37a"
......@@ -9571,11 +9561,6 @@ react-error-overlay@^6.0.9:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==
 
react-fast-compare@^3.0.1:
version "3.2.0"
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb"
integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==
react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
......@@ -9586,19 +9571,6 @@ react-is@^17.0.1:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.1.tgz#5b3531bd76a645a4c9fb6e693ed36419e3301339"
integrity sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==
 
react-onclickoutside@^6.10.0:
version "6.11.2"
resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.11.2.tgz#790e2100b9a3589eefca1404ecbf0476b81b7928"
integrity sha512-640486eSwU/t5iD6yeTlefma8dI3bxPXD93hM9JGKyYITAd0P1JFkkcDeyHZRqNpY/fv1YW0Fad9BXr44OY8wQ==
react-popper@^2.2.5:
version "2.2.5"
resolved "https://registry.yarnpkg.com/react-popper/-/react-popper-2.2.5.tgz#1214ef3cec86330a171671a4fbcbeeb65ee58e96"
integrity sha512-kxGkS80eQGtLl18+uig1UIf9MKixFSyPxglsgLBxlYnyDf65BiY9B3nZSc6C9XUNDgStROB0fMQlTEz1KxGddw==
dependencies:
react-fast-compare "^3.0.1"
warning "^4.0.2"
react-refresh@^0.8.3:
version "0.8.3"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f"
......@@ -9699,6 +9671,13 @@ react-scripts@4.0.3:
optionalDependencies:
fsevents "^2.1.3"
 
react-toastify@^7.0.4:
version "7.0.4"
resolved "https://registry.yarnpkg.com/react-toastify/-/react-toastify-7.0.4.tgz#7d0b743f2b96f65754264ca6eae31911a82378db"
integrity sha512-Rol7+Cn39hZp5hQ/k6CbMNE2CKYV9E5OQdC/hBLtIQU2xz7DdAm7xil4NITQTHR6zEbE5RVFbpgSwTD7xRGLeQ==
dependencies:
clsx "^1.1.1"
react@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
......@@ -11694,13 +11673,6 @@ walker@^1.0.7, walker@~1.0.5:
dependencies:
makeerror "1.0.x"
 
warning@^4.0.2:
version "4.0.3"
resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
dependencies:
loose-envify "^1.0.0"
watchpack-chokidar2@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957"
......