Skip to content
Snippets Groups Projects
Commit 4364dd76 authored by Hugo SUBTIL's avatar Hugo SUBTIL
Browse files

Merge branch 'feat/pipeline' into 'dev'

Feat/pipeline

See merge request web-et-numerique/llle_project/backoffice-client!4
parents 38c46b08 32684405
No related branches found
No related tags found
2 merge requests!7feat: add front office,!4Feat/pipeline
Pipeline #15416 passed
image: docker:git
services:
- docker:dind
variables:
DOCKER_DRIVER: overlay2
DOCKER_TLS_CERTDIR: ''
stages:
- build
- quality
build-test:
stage: build
image: node:14.15.4-alpine
before_script:
- apk add git
- apk add bash
script:
- yarn
- yarn build
only:
- dev
- merge_requests
build:
image: docker:18.09
services:
- docker:18.09-dind
stage: build
only:
- master
- dev
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build --pull -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG" --build-arg conf=prod .
- docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG"
sonarqube:
stage: quality
only:
- dev
- merge_requests
image: registry.forge.grandlyon.com/apoyen2/sonnar-scanner-gl:master
before_script:
- export NODE_PATH=$NODE_PATH:`npm root -g`
- npm install -g typescript
script:
- >
sonar-scanner
-Dsonar.projectName="ecolyo-backoffice-front"
-Dsonar.projectVersion=1.0
-Dsonar.sourceEncoding=UTF-8
-Dsonar.projectBaseDir=.
-Dsonar.host.url=${SONAR_URL}
-Dsonar.projectKey=${CI_PROJECT_PATH_SLUG}
-Dsonar.login=${SONAR_TOKEN}
-Dsonar.cpd.exclusions=tests/**,src/**/*.spec.ts*
-Dsonar.qualitygate.wait=true
import { useState, useEffect } from 'react'
import { BrowserRouter } from 'react-router-dom'
import Layout from './components/Layout/Layout'
import Routes from './components/Routes/Routes'
import { useAuth } from './hooks/useAuth'
import { UserContext } from './hooks/userContext'
import { User } from './models/user.model'
import { ToastContainer } from 'react-toastify'
import 'react-toastify/dist/ReactToastify.css'
function App() {
const { loginUser, error, isUserLogged, getUser, logoutUser } = useAuth()
const [isLogged, setisLogged] = useState<boolean>(false)
const [user, setuser] = useState<User>()
import useFindUser from './hooks/useFindUser'
useEffect(() => {
let subscribed = true
async function checkIsLogged() {
const userLogged = await isUserLogged()
if (userLogged) {
setisLogged(true)
setuser(getUser() as User)
} else setisLogged(false)
}
if (subscribed) checkIsLogged()
return () => {
subscribed = false
}
}, [isLogged, setisLogged])
function App() {
const { user, setUser, isLoading } = useFindUser()
return (
<BrowserRouter>
<UserContext.Provider
value={{ user, loginUser, error, isLogged, logoutUser, setisLogged }}
>
<UserContext.Provider value={{ user, setUser, isLoading }}>
<Layout>
<Routes />
</Layout>
......
......@@ -142,7 +142,6 @@ const Editing: React.FC = () => {
setIsTouched(false)
}
}
setisLoading(false)
}
if (subscribed) {
......@@ -152,7 +151,7 @@ const Editing: React.FC = () => {
subscribed = false
setRefreshData(false)
}
}, [date, user, refreshData])
}, [date, user, refreshData, resetFields])
return (
<>
......
import React, { useContext } from 'react'
import React from 'react'
import { useAuth } from '../../hooks/useAuth'
import { UserContext } from '../../hooks/userContext'
import './login.scss'
const Login: React.FC = () => {
const { loginUser, setisLogged } = useContext(UserContext)
const handleClickLogin = async () => {
if (loginUser && setisLogged) {
await loginUser()
setisLogged(true)
}
}
const { loginUser } = useAuth()
return (
<div className="login">
<div className="container">
<h1>Bienvenue sur le Backoffice d'Ecolyo !</h1>
<button className="btnValid" onClick={handleClickLogin}>
<button className="btnValid" onClick={loginUser}>
Login
</button>
</div>
......
......@@ -4,16 +4,11 @@ import logo from '../../assets/icons/ecolyo-logo.svg'
import './menu.scss'
import { NavLink } from 'react-router-dom'
import { UserContext } from '../../hooks/userContext'
import { useAuth } from '../../hooks/useAuth'
const Menu: React.FC = () => {
const { isLogged, logoutUser, setisLogged } = useContext(UserContext)
const handleLogout = () => {
if (logoutUser && setisLogged) {
logoutUser()
setisLogged(false)
}
}
const { user } = useContext(UserContext)
const { logoutUser } = useAuth()
return (
<nav className={'menu'}>
<div className="logo-container">
......@@ -29,8 +24,8 @@ const Menu: React.FC = () => {
})}
</div>
<div className="administration">
{isLogged ? (
<button className="btnValid logButton" onClick={handleLogout}>
{user ? (
<button className="btnValid logButton" onClick={logoutUser}>
Logout
</button>
) : (
......
......@@ -34,7 +34,9 @@ const MonthlyNews: React.FC<MonthlyNewsProps> = ({
'undo redo | bold italic underline | alignleft aligncenter alignright | code | ecolyoLink',
}}
value={header}
onEditorChange={(newHeader) => handleChange(newHeader, 'header')}
onEditorChange={(newHeader: string) =>
handleChange(newHeader, 'header')
}
/>
<div className="subtitle">
<p className="title">Citation du mois</p>
......@@ -102,7 +104,7 @@ const MonthlyNews: React.FC<MonthlyNewsProps> = ({
},
}}
value={quote}
onEditorChange={(newQuote) => handleChange(newQuote, 'quote')}
onEditorChange={(newQuote: string) => handleChange(newQuote, 'quote')}
/>
<div className="buttons">
<button className="btnCancel" onClick={onCancel}>
......
import React, { useContext } from 'react'
import { NavLink } from 'react-router-dom'
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'
import { useAuth } from '../../hooks/useAuth'
const Navbar: React.FC = () => {
const { isLogged, logoutUser } = useContext(UserContext)
const { user } = useContext(UserContext)
const { logoutUser } = useAuth()
return (
<div className="navbar">
<img src={logo} alt="Ecolyo logo" className="logo" />
<div className="menu-list">
<NavLink to={'/editing'} activeClassName="active">
<img src={editing} className="navbar-icon" alt="Editing icon" />
......@@ -23,15 +20,12 @@ const Navbar: React.FC = () => {
<img src={settings} className="navbar-icon" alt="Settings icon" />
Paramètres
</NavLink>
{isLogged ? (
<p onClick={logoutUser}>Logout</p>
) : (
<NavLink to="/login" activeClassName="active">
<img src={login} className="navbar-icon" alt="Login icon" />
Login
</NavLink>
)}
</div>
{user && (
<button className="btnValid logButton" onClick={logoutUser}>
Logout
</button>
)}
</div>
)
}
......
......@@ -16,12 +16,6 @@
align-items: center;
justify-content: center;
}
.burger,
.logo {
width: 2rem;
left: 1rem;
position: absolute;
}
a {
text-decoration: none;
display: flex;
......@@ -41,4 +35,10 @@
.navbar-icon {
width: 1.3rem;
}
.logButton {
width: 100px;
min-width: 0;
margin-left: auto;
margin-top: 0;
}
}
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
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: string) =>
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
......@@ -13,9 +13,9 @@ const PrivateRoute: React.FC<PrivateRouteProps> = ({
path,
exact,
}: PrivateRouteProps) => {
const { isLogged } = useContext(UserContext)
const { user } = useContext(UserContext)
return isLogged ? (
return user ? (
<Route path={path} exact={exact} component={component} />
) : (
<Redirect to="/login" />
......
......@@ -7,11 +7,11 @@ import Settings from '../Settings/Settings'
import PrivateRoute from './PrivateRoute'
const Routes: React.FC = () => {
const { isLogged } = useContext(UserContext)
const { user } = useContext(UserContext)
return (
<Switch>
{isLogged && <Redirect path="/login" to="/editing" />}
{user && <Redirect path="/login" to="/editing" />}
<Route path="/login" component={Login} />
<PrivateRoute path="/editing" component={Editing} exact />
<PrivateRoute path="/settings" component={Settings} exact />
......
import React, { useState } from 'react'
import { useContext, useState } from 'react'
import axios from 'axios'
import { User } from '../models/user.model'
import { UserContext } from './userContext'
import { useHistory } from 'react-router-dom'
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)
const { setUser } = useContext(UserContext)
const history = useHistory()
//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))
}
await setUserContext()
} catch (e) {
setError(e)
}
}
const logoutUser = (): void => {
localStorage.removeItem('user')
const logoutUser = async (): Promise<void> => {
try {
if (setUser) setUser(null)
await axios.get(`${_apiUrl}Logout`)
} catch (e) {
setError(e)
}
}
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
//set user in context and push them home
const setUserContext = async (): Promise<void> => {
try {
const { data } = await axios.get(`${_apiUrl}api/common/WhoAmI`)
if (data && setUser) {
setUser(data)
console.log('usertoContext', data)
history.push('/editing')
}
} else {
return false
} catch (e) {
setError(e)
}
}
const getUser = (): User | undefined => {
const user = localStorage.getItem('user')
if (user) return JSON.parse(user) as User
}
return { loginUser, error, isUserLogged, getUser, logoutUser }
return { loginUser, error, logoutUser }
}
import { useState, useEffect } from 'react'
import axios from 'axios'
import { User } from '../models/user.model'
const useFindUser = () => {
const [user, setUser] = useState<User | null>(null)
const [isLoading, setLoading] = useState<boolean>(true)
const _apiUrl: string = 'https://localhost:1443/'
useEffect(() => {
async function findUser() {
const { data } = await axios.get(`${_apiUrl}api/common/WhoAmI`)
if (data) {
setUser(data)
setLoading(false)
}
}
findUser()
}, [])
return {
user,
setUser,
isLoading,
}
}
export default useFindUser
import React, { createContext, Dispatch, SetStateAction } from 'react'
import { 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>>
user: User | null
setUser: Dispatch<SetStateAction<User | null>>
isLoading: boolean
}
export const UserContext = createContext<Partial<UserContextProps>>({})
......@@ -58,9 +58,9 @@ export class MonthlyNewsService {
},
}
)
if (data == {}) {
return null
}
// if (data == {}) {
// return null
// }
return data as IMonthlyNews
} catch (e) {
......@@ -86,9 +86,9 @@ export class MonthlyNewsService {
},
}
)
if (data === {}) {
return null
}
// if (data === {}) {
// return null
// }
return data as IPoll
} catch (e) {
console.log('error', e)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment