Compare commits

..

2 Commits

Author SHA1 Message Date
Huaoe 7d70b308cf gitignore 2019-09-17 11:29:36 +02:00
Huaoe 077df03406 after merge 2019-09-17 11:28:32 +02:00
321 changed files with 22361 additions and 91491 deletions
+4
View File
@@ -0,0 +1,4 @@
/nextjs/node_modules/
/node_modules/
/nextjs/node_modules/
/jenkins/
-3
View File
@@ -1,3 +0,0 @@
{
"git.ignoreLimitWarning": true
}
-1
View File
@@ -1 +0,0 @@
/volume/
-50
View File
@@ -1,50 +0,0 @@
CLIENT=tt-app
DOCKERCOMPOSE := $(shell command -v docker-compose 2> /dev/null)
USAGE := Usage: make ENV={prod|preprod|dev} {SYS=windows|linux} {docker-build|docker-start|docker-stop|docker-restart}
ifndef DOCKERCOMPOSE
$(error docker-compose is not available)
endif
ifndef ENV
$(info Environment variable is not set)
$(info $(USAGE))
$(error Exiting)
endif
SYS=linux
DC_OVERRIDE := $(shell test -e conf/docker-compose.override.yml && echo "--file conf/docker-compose.override.yml")
DC_OVERRIDE_ENV := $(shell test -e conf/docker-compose.$(ENV).yml && echo "--file conf/docker-compose.$(ENV).yml")
ifeq ($(SYS),linux)
DC=ENV=$(ENV) CLIENT=$(CLIENT) "$(DOCKERCOMPOSE)" --project-name "$(CLIENT)_$(ENV)" --file conf/docker-compose.yml $(DC_OVERRIDE) $(DC_OVERRIDE_ENV)
else
DC=ENV=$(ENV) CLIENT=$(CLIENT) "$(DOCKERCOMPOSE)" --project-name "$(CLIENT)_$(ENV)" --file conf/docker-compose.yml $(DC_OVERRIDE) $(DC_OVERRIDE_ENV)
endif
default:
$(info $(USAGE))
$(error Exiting)
docker-build:
$(DC) build
$(DC) up -d
docker-start:
$(DC) start
docker-stop:
$(DC) stop
docker-restart: docker-stop docker-start
docker-rm: docker-stop
$(DC) rm
sys:
@echo $(SYS)
@echo $(DC)
-28
View File
@@ -1,28 +0,0 @@
## 1. Droits
mot de pass de depart (juste pour info, pas d'utilité)
Jenkins : 8c628b7abfe242a397ac7fbedfd4de8c
Besoin d'effectuer la commande sudo chmod 666 /var/run/docker.sock dans le container Jenkins.
docker exec -it --user root $(containerName) /bin/bash
docker exec -it -u 0 60344f0b414b bash
## 2. post install
Installer yarn
## 3. run
localhost:8080
>stop curent TTapp dev run to free 3000 port
### 1. login:password
>sglatz:yVqSfBDRPp07
### 2. gitea password
>tt-jenkins:
#### 2. As Kanye West said:
> We're living the future so
> the present is our past.
-17
View File
@@ -1,17 +0,0 @@
version: '2'
services:
jenkins:
hostname: jenkins
image: jenkinsci/blueocean
ports:
- '8080:8080'
- '50000:50000'
privileged: true
volumes:
# enable persistent volume (warning: make sure that the local jenkins_home folder is created)
- '../volume/jenkins_data:/var/jenkins_home'
- '/var/run/docker.sock:/var/run/docker.sock'
restart: always
volumes:
jenkins_data:
-5
View File
@@ -1,5 +0,0 @@
{
"dependencies": {
"cypress": "^3.4.1"
}
}
-1217
View File
File diff suppressed because it is too large Load Diff
+25
View File
@@ -0,0 +1,25 @@
SERVER_URL=http://localhost:80
MONGO_URI=mongodb://declic:declic42@ds115653.mlab.com:15653/next-auth
FACEBOOK_ID=2332071840142634
FACEBOOK_SECRET=afb8bbca72bd8c517c64f81e998e4f12
PROD_FACEBOOK_ID=1800752833559014
PROD_FACEBOOK_SECRET=454de729b1e58f506f94c8b50ca5c011
TT_LINKEDIN_ID=86m6hegwyj8lbo
TT_LINKEDIN_SECRET=LIOibqDszsP2vQSr
LINKEDIN_ID=77k1m8qx7w6ygj
LINKEDIN_SECRET=mbcnVjyy2vqAZz1B
GOOGLE_ID=
GOOGLE_SECRET=
TWITTER_KEY=
TWITTER_SECRET=
EMAIL_FROM=contact@application.bzh
EMAIL_SERVER=mail.gandi.net
EMAIL_PORT=587
EMAIL_SECURE=true
EMAIL_USERNAME=noreply@application.bzh
EMAIL_PASSWORD=PWApwaPWApwa56!!!
FIREBASE_API_KEY=AAAAHlF5rsI:APA91bHXvjGDJRLzVvqmBDPM1Et96Bw0Iuvc7EGe9wt4a_lSJijDlbZ3RT96seLDK-QM6Mf8qQ4dH6MI9iWt1_d3uzKG2bxr56zltglZ3Z9xU8gz2iJeRGmlOd0YdV43IumIVe6dIOr-
RECAPTCHA_VERIFY_URL=https://www.google.com/recaptcha/api/siteverify
RECAPTCHA_SECRET=6LcCvHcUAAAAAIG-_iR5AXqkwxINfgqxKZ_kG244
MJ_APIKEY_PUBLIC=355697fac93fca865660734b4fdffaeb
MJ_APIKEY_PRIVATE=ddecf75321ca89c09e561857b13534c8
+2 -6
View File
@@ -1,8 +1,4 @@
/node_modules/
.next/
.env
ecosystem.config.js
yarn-error.log
robots.txt
/out/
yarn.lock
.gitignore
-18
View File
@@ -1,18 +0,0 @@
FROM keymetrics/pm2:8-alpine
ENV TERM=xterm
# RUN pm2 -V
RUN apk --no-cache update \
&& apk --no-cache add g++ make bash zlib-dev libpng-dev \
&& rm -fr /var/cache/apk/*
RUN apk add --no-cache curl
RUN apk add --no-cache bash
RUN apk add --no-cache yarn
CMD cd /home/app/nextjs && yarn cache dir && yarn cache clean && yarn install && yarn build && pm2 startOrReload ecosystem.config.js --env production --no-daemon
-43
View File
@@ -1,43 +0,0 @@
pipeline {
agent {
docker {
image 'mhart/alpine-node:latest'
args '-p 3000:3000'
}
// dockerfile true
}
environment {
CI = 'true'
}
stages {
stage('Prepare') {
steps {
// withEnv(['PATH+NODE=/usr/local/bin/node']) {
// echo 'Prepare step started ... '
// sh 'echo prefix = ~/.node >> ~/.npmrc'
// sh 'whoami'
// sh 'chown -R node:node /usr/local/lib/node_modules'
sh 'cd /var/jenkins_home/workspace/tt-app_app_Saga/nextjs/'
sh 'yarn install'
// }
}
}
stage('Build') {
steps {
echo 'Build step started ... '
sh '/var/jenkins_home/workspace/tt-app_app_Saga/nextjs/scripts/start.sh'
}
}
stage('Test') {
steps {
sh '/var/jenkins_home/workspace/tt-app_app_Saga/nextjs/scripts/test.sh'
}
}
stage('Response') {
steps {
echo 'Vous pouvez pull sur la production'
sh '/var/jenkins_home/workspace/tt-app_app_Saga/nextjs/scripts/kill.sh'
}
}
}
}
+2 -44
View File
@@ -2,17 +2,16 @@
## How to use
Download the example [or clone the repo](https://git.e-declic.net/talents-tube/app.git):
Download the example [or clone the repo](https://github.com/mui-org/material-ui):
```bash
git clone
git clone
```
Install it and run:
```bash
yarn install
yarn build
yarn dev
```
@@ -25,44 +24,3 @@ yarn dev
[Redux-Saga]
https://redux-saga.js.org/docs/basics/ErrorHandling.html
is a library that aims to make application side effect asynchronous things like data fetching and impure things like accessing the browser cache
## Integration
### Naming conventions
style classes name syntax : Camel case
Try to name without too much precision
### Material UI
[components/atoms/theme.js] Const file
[components/atoms/] Atomic components
[components/organisms] General components
[components/templates] Layouts components
## MEP
=================================
Mise en PRE-production de lapplication PWA
=================================
Aller dans la preproduction et git pull dans le répertoire /app (pas www)
Possibilité de devoir git stash
Attention de bien avoir le .env
Restart docker preproduction (sudo make ENV=preprod docker-restart)
sudo docker exec -it frontnginx.nginx bash
nginx -t && nginx -s reload
## Test
### Cypress
[Gmail-tester]
https://github.com/levz0r/gmail-tester
## Continuous Integration
### Jenkins
> in case of emergency
> make docker-restart ENV=dev
> adduser jenkins root
View File
+27 -47
View File
@@ -1,83 +1,63 @@
import {
FETCH_JOBS_REQUEST,
FETCH_JOBS_SUCCESS,
FETCH_JOBS_FAILURE,
FETCH_JOB_REQUEST,
FETCH_JOB_SUCCESS,
FETCH_JOB_FAILURE,
FETCH_EMPHASIS_JOBS_REQUEST,
FETCH_EMPHASIS_JOBS_SUCCESS,
FETCH_EMPHASIS_JOBS_FAILURE,
CLEAR_AD,
COUNT_AD_VIEW,
TOGGLE_PROMOTED_FILTER_ADS
FETCH_ADS_REQUEST,
FETCH_ADS_SUCCESS,
FETCH_ADS_FAILURE,
FETCH_AD_REQUEST,
FETCH_AD_SUCCESS,
FETCH_AD_FAILURE,
FETCH_PROMOTED_ADS_REQUEST,
FETCH_PROMOTED_ADS_SUCCESS,
FETCH_PROMOTED_ADS_FAILURE,
} from '../types'
//Ads stat count
export const countAdViewRequest = (id) => ({
type: COUNT_AD_VIEW,
id
});
//Is ads promoted?
export const togglePromotedFilterRequest = () => ({
type: TOGGLE_PROMOTED_FILTER_ADS
});
//Ads list
export const fetchJobsRequest = (payload) => ({
type: FETCH_JOBS_REQUEST,
export const fetchAdsRequest = (payload) => ({
type: FETCH_ADS_REQUEST,
payload
});
export const fetchJobsSuccess = res => ({
type: FETCH_JOBS_SUCCESS,
export const fetchAdsSuccess = res => ({
type: FETCH_ADS_SUCCESS,
res
});
export const fetchJobsFailure = res => ({
type: FETCH_JOBS_FAILURE,
export const fetchAdsFailure = res => ({
type: FETCH_ADS_FAILURE,
res
});
//Ads list
export const fetchEmphasisJobsRequest = (payload) => ({
type: FETCH_EMPHASIS_JOBS_REQUEST,
export const fetchPromotedAdsRequest = (payload) => ({
type: FETCH_PROMOTED_ADS_REQUEST,
payload
});
export const fetchEmphasisJobsSuccess = res => ({
type: FETCH_EMPHASIS_JOBS_SUCCESS,
export const fetchPromotedAdsSuccess = res => ({
type: FETCH_PROMOTED_ADS_SUCCESS,
res
});
export const fetchEmphasisJobsFailure = res => ({
type: FETCH_EMPHASIS_JOBS_FAILURE,
export const fetchPromotedAdsFailure = res => ({
type: FETCH_PROMOTED_ADS_FAILURE,
res
});
//Single ad
export const fetchJobRequest = payload => ({
type: FETCH_JOB_REQUEST,
export const fetchAdRequest = payload => ({
type: FETCH_AD_REQUEST,
payload
});
export const fetchJobSuccess = res => ({
type: FETCH_JOB_SUCCESS,
export const fetchAdSuccess = res => ({
type: FETCH_AD_SUCCESS,
res
});
export const fetchJobFailure = res => ({
type: FETCH_JOB_FAILURE,
export const fetchAdFailure = res => ({
type: FETCH_AD_FAILURE,
res
});
//clear ad
export const clearAd = res => ({
type: CLEAR_AD
});
-94
View File
@@ -1,94 +0,0 @@
import {
POST_AD_ANSWER_REQUEST,
POST_AD_ANSWER_FAILURE,
POST_AD_ANSWER_SUCCESS,
FETCH_JOBS_ANSWER_REQUEST,
FETCH_JOBS_ANSWER_SUCCESS,
FETCH_JOBS_ANSWER_FAILURE,
FETCH_ANSWER_REQUEST,
FETCH_ANSWER_SUCCESS,
FETCH_ANSWER_FAILURE,
POST_MESSAGE_ANSWER_REQUEST,
POST_MESSAGE_ANSWER_FAILURE,
POST_MESSAGE_ANSWER_SUCCESS,
FETCH_ANSWER_MESAGES_REQUEST,
FETCH_ANSWER_MESAGES_FAILURE,
FETCH_ANSWER_MESAGES_SUCCESS,
} from "../types";
export const postAdAnswerRequest = payload => ({
type: POST_AD_ANSWER_REQUEST,
payload
});
export const postAdAnswerRequestFailure = errors => ({
type: POST_AD_ANSWER_FAILURE,
errors
});
export const postAdAnswerRequestSuccess = res => ({
type: POST_AD_ANSWER_SUCCESS,
res
});
export const postMessageAnswerRequest = payload => ({
type: POST_MESSAGE_ANSWER_REQUEST,
payload
});
export const postMessageAnswerFailure = errors => ({
type: POST_MESSAGE_ANSWER_FAILURE,
errors
});
export const postMessageAnswerSuccess = res => ({
type: POST_MESSAGE_ANSWER_SUCCESS,
res
});
export const fetchJobsAnsweredRequest = payload => ({
type: FETCH_JOBS_ANSWER_REQUEST,
payload
});
export const fetchJobsAnsweredSuccess = res => ({
type: FETCH_JOBS_ANSWER_SUCCESS,
res
});
export const fetchJobsAnsweredFailure = errors => ({
type: FETCH_JOBS_ANSWER_FAILURE,
errors
});
export const fetchAnswerRequest = payload => ({
type: FETCH_ANSWER_REQUEST,
payload
});
export const fetchAnswerSuccess = res => ({
type: FETCH_ANSWER_SUCCESS,
res
});
export const fetchAnswerFailure = errors => ({
type: FETCH_ANSWER_FAILURE,
errors
});
export const fetchAnswerMessagesRequest = payload => ({
type: FETCH_ANSWER_MESAGES_REQUEST,
payload
});
export const fetchAnswerMessagesSuccess = res => ({
type: FETCH_ANSWER_MESAGES_SUCCESS,
res
});
export const fetchAnswerMessagesFailure = errors => ({
type: FETCH_ANSWER_MESAGES_FAILURE,
errors
});
+13 -64
View File
@@ -2,73 +2,22 @@ import {
FETCH_COMPANIES_REQUEST,
FETCH_COMPANIES_SUCCESS,
FETCH_COMPANIES_FAILURE,
FETCH_COMPANY_REQUEST,
FETCH_COMPANY_SUCCESS,
FETCH_COMPANY_FAILURE,
FETCH_EMPHASIS_COMPANIES_REQUEST,
FETCH_EMPHASIS_COMPANIES_SUCCESS,
FETCH_EMPHASIS_COMPANIES_FAILURE,
CLEAR_COMPANY,
COUNT_COMPANY_VIEW,
} from '../types'
//COMPANIES list
export const fetchCompaniesRequest = (payload) => ({
type: FETCH_COMPANIES_REQUEST,
payload
});
export const fetchCompaniesSuccess = res => ({
type: FETCH_COMPANIES_SUCCESS,
res
});
export const fetchCompaniesFailure = res => ({
type: FETCH_COMPANIES_FAILURE,
res
});
//COMPANY single
export const countCompanyViewRequest = (id) => ({
type: COUNT_COMPANY_VIEW,
id
});
export const fetchCompanyRequest = payload => ({
type: FETCH_COMPANY_REQUEST,
payload
});
export const fetchCompanySuccess = res => ({
type: FETCH_COMPANY_SUCCESS,
res
});
export const fetchCompanyFailure = res => ({
type: FETCH_COMPANY_FAILURE,
res
});
//EMPHASIS 'aka mise en avant'
export const fetchEmphasisCompaniesRequest = (payload) => ({
type: FETCH_EMPHASIS_COMPANIES_REQUEST,
payload
});
export const fetchEmphasisCompaniesSuccess = res => ({
type: FETCH_EMPHASIS_COMPANIES_SUCCESS,
res
});
export const fetchEmphasisCompaniesFailure = res => ({
type: FETCH_EMPHASIS_COMPANIES_FAILURE,
res
});
//clear ad
export const clearCompany = res => ({
type: CLEAR_COMPANY
});
type: FETCH_COMPANIES_REQUEST,
payload
});
export const fetchCompaniesSuccess = res => ({
type: FETCH_COMPANIES_SUCCESS,
res
});
export const fetchCompaniesFailure = res => ({
type: FETCH_COMPANIES_FAILURE,
res
});
-43
View File
@@ -1,43 +0,0 @@
import {
UPLOAD_MEDIA_REQUEST,
UPLOAD_MEDIA_FAILURE,
UPLOAD_MEDIA_SUCCESS,
UPLOAD_MEDIA_PRES_REQUEST,
UPLOAD_MEDIA_PRES_FAILURE,
UPLOAD_MEDIA_PRES_SUCCESS,
} from "../types";
export const uploadMedia = payload => ({
type: UPLOAD_MEDIA_REQUEST,
payload
});
export const uploadMediaFailure = errors => ({
type: UPLOAD_MEDIA_FAILURE,
errors
});
export const uploadMediaSuccess = res => ({
type: UPLOAD_MEDIA_SUCCESS,
res
});
export const uploadMediaPres = payload => ({
type: UPLOAD_MEDIA_PRES_REQUEST,
payload
});
export const uploadMediaPresFailure = errors => ({
type: UPLOAD_MEDIA_PRES_FAILURE,
errors
});
export const uploadMediaPresSuccess = res => ({
type: UPLOAD_MEDIA_PRES_SUCCESS,
res
});
-25
View File
@@ -1,25 +0,0 @@
import {
UPLOAD_MEDIA_CV_REQUEST,
UPLOAD_MEDIA_CV_FAILURE,
UPLOAD_MEDIA_CV_SUCCESS,
} from "../types";
export const uploadMediaCv = payload => ({
type: UPLOAD_MEDIA_CV_REQUEST,
payload
});
export const uploadMediaCvFailure = errors => ({
type: UPLOAD_MEDIA_CV_FAILURE,
errors
});
export const uploadMediaCvSuccess = res => ({
type: UPLOAD_MEDIA_CV_SUCCESS,
res
});
+4 -127
View File
@@ -7,45 +7,8 @@ import {
SUBSCRIBE_NEWSLETTER_FAILURE,
REQUEST_REGISTER,
REQUEST_REGISTER_SUCCESS,
REQUEST_REGISTER_FAILURE,
ACCOUNT_CONFIRMATION_REQUEST,
ACCOUNT_CONFIRMATION_SUCCESS,
ACCOUNT_CONFIRMATION_FAILURE,
SEND_CONFIRMATION_EMAIL_REQUEST,
SEND_CONFIRMATION_EMAIL_SUCCESS,
SEND_CONFIRMATION_EMAIL_FAILURE,
UPDATE_USER_REQUEST,
UPDATE_USER_SUCCESS,
UPDATE_USER_FAILURE,
RESET_PASSWORD_REQUEST,
RESET_PASSWORD_SUCCESS,
RESET_PASSWORD_FAILURE,
SUBSCRIBE_USER_TO_PUSH_REQUEST,
SUBSCRIBE_USER_TO_PUSH_SUCCESS,
SUBSCRIBE_USER_TO_PUSH_FAILURE,
FETCH_USER_SUBSCRIPTION_TO_PUSH_REQUEST,
FETCH_USER_SUBSCRIPTION_TO_PUSH_SUCCESS,
FETCH_USER_SUBSCRIPTION_TO_PUSH_FAILURE,
UPDATE_USER_PICTURE_REQUEST,
UPDATE_USER_PICTURE_SUCCESS,
UPDATE_USER_PICTURE_FAILURE
REQUEST_REGISTER_FAILURE
} from '../types'
export const resetPasswordRequest = (payload) => ({
type: RESET_PASSWORD_REQUEST,
payload
});
export const resetPasswordSuccess = () => ({
type: RESET_PASSWORD_SUCCESS,
});
export const resetPasswordFailure = (err) => ({
type: RESET_PASSWORD_FAILURE,
err
});
export const fetchCurrentUserRequest = () => ({
type: FETCH_CURRENT_USER_REQUEST
});
@@ -67,7 +30,7 @@ export const registerUserRequest = (payload) => ({
export const registerUserSuccess = () => ({
type: REQUEST_REGISTER_SUCCESS,
});
export const registerUserFailure = (err) => ({
@@ -75,20 +38,6 @@ export const registerUserFailure = (err) => ({
err
});
export const sendConfirmationEmailRequest = (payload) => ({
type: SEND_CONFIRMATION_EMAIL_REQUEST,
payload
});
export const sendConfirmationEmailSuccess = (payload) => ({
type: SEND_CONFIRMATION_EMAIL_SUCCESS,
});
export const sendConfirmationEmailFailure = (err) => ({
type: SEND_CONFIRMATION_EMAIL_FAILURE,
err
});
export const subscribeToNewsletterRequest = (payload) => ({
type: SUBSCRIBE_NEWSLETTER_REQUEST,
payload
@@ -98,78 +47,6 @@ export const subscribeToNewsletterSuccess = () => ({
type: SUBSCRIBE_NEWSLETTER_SUCCESS,
});
export const subscribeToNewsletterFailure = (err) => ({
export const subscribeToNewsletterFailure = () => ({
type: SUBSCRIBE_NEWSLETTER_FAILURE,
err
});
export const requestConfirmationAccountRequest = (payload) => ({
type: ACCOUNT_CONFIRMATION_REQUEST,
payload
});
export const requestConfirmationAccountSuccess = () => ({
type: ACCOUNT_CONFIRMATION_SUCCESS,
});
export const requestConfirmationAccountFailure = (err) => ({
type: ACCOUNT_CONFIRMATION_FAILURE,
err
});
export const updateUserRequest = (payload) => ({
type: UPDATE_USER_REQUEST,
payload
});
export const updateUserRequestSuccess = () => ({
type: UPDATE_USER_SUCCESS,
});
export const updateUserRequestFailure = (err) => ({
type: UPDATE_USER_FAILURE,
err
});
export const subscribeUserToPushRequest = (payload) => ({
type: SUBSCRIBE_USER_TO_PUSH_REQUEST,
payload
});
export const subscribeUserToPushSuccess = () => ({
type: SUBSCRIBE_USER_TO_PUSH_SUCCESS,
});
export const subscribeUserToPushFailure = (err) => ({
type: SUBSCRIBE_USER_TO_PUSH_FAILURE,
err
});
export const fetchUserSubscriptionToPushRequest = (payload) => ({
type: FETCH_USER_SUBSCRIPTION_TO_PUSH_REQUEST,
payload
});
export const fetchUserSubscriptionToPushSuccess = (res) => ({
type: FETCH_USER_SUBSCRIPTION_TO_PUSH_SUCCESS,
res
});
export const fetchUserSubscriptionToPushFailure = (err) => ({
type: FETCH_USER_SUBSCRIPTION_TO_PUSH_FAILURE,
err
});
export const updateUserPictureRequest = (payload) => ({
type: UPDATE_USER_PICTURE_REQUEST,
payload
})
export const updateUserPictureSuccess = (data) => ({
type: UPDATE_USER_PICTURE_SUCCESS,
data
})
export const updateUserPictureFailure = (err) => ({
type: UPDATE_USER_PICTURE_FAILURE,
err
})
});
-18
View File
@@ -1,18 +0,0 @@
import { withRouter } from 'next/router';
import Link from 'next/link';
import React, { Children } from 'react';
const ActiveLink = ({ router, children, ...props }) => {
const child = Children.only(children);
let className = child.props.className || '';
if (router.pathname === props.href && props.activeClassName) {
className = `${className} ${props.activeClassName}`.trim();
}
delete props.activeClassName;
return <Link {...props}>{React.cloneElement(child, { className })}</Link>;
};
export default withRouter(ActiveLink);
-94
View File
@@ -1,94 +0,0 @@
import React, { Fragment } from 'react'
import { useSelector } from 'react-redux'
import { Typography } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import VideoVimeo from './VideoVimeo'
import ChatCardMessage from './ChatCardMessage'
import _ from "lodash"
import Ar from "lodash/array"
const useStyles = makeStyles(theme => ({
card: {
width: '100%',
},
userMessage: {
display: 'flex',
alignItems: 'flex-end',
},
messageSender: {
fontSize: '0.9em',
fontWeight: '300',
color: theme.palette.primary.important,
},
messageContent: {
fontWeight: '300',
color: theme.palette.secondary.main,
},
messageDate: {
fontSize: '0.8em',
fontWeight: '300',
color: theme.palette.primary.dark,
padding: theme.spacing(2,0),
},
currentUserBubble: {
background: theme.palette.primary.important,
alignSelf: 'flex-end',
},
currentMessageSender: {
color: theme.palette.primary.important,
},
otherUserBubble: {
background: theme.palette.primary.main,
alignSelf: 'flex-start',
},
otherMessageSender: {
color: theme.palette.primary.main,
},
avatar: {
width: '2.5em',
borderRadius: '50%',
margin: theme.spacing(0,1),
},
videoVimeo: {
[theme.breakpoints.up('md')]: {
paddingBottom: '55%',
},
},
}));
export default function ChatCard(props) {
const classes = useStyles();
const userFirstName = useSelector(state => state.user.firstname);
const userLastName = useSelector(state => state.user.lastname);
const userPicture = useSelector(state => state.user.picture);
const bubbleClass = (userFirstName === props.message.sender.firstname && userLastName === props.message.sender.lastname) ? classes.currentUserBubble : classes.otherUserBubble
const messageSenderClass = (userFirstName === props.message.sender.firstname && userLastName === props.message.sender.lastname) ? classes.currentMessageSender : classes.otherMessageSender
const bubbleSide = (userFirstName === props.message.sender.firstname && userLastName === props.message.sender.lastname) ? 'right' : 'left'
return (
<Fragment>
<ChatCardMessage side={bubbleSide} firstname={props.message.sender.firstname} lastname={props.message.sender.lastname} picture={userPicture}
video={
(props.message.video)
? true :
false}
message={
(props.message.video)
? (<VideoVimeo classesOverride={ classes.videoVimeo } videoId={Ar.last(_.split(props.message.video.cdn_url, '/'))} />)
: props.message.content}
messageTexte = {props.message.content}
messageSenderClass={messageSenderClass} bubbleClass={bubbleClass}/>
<Typography
className={classes.messageDate}
align="center"
>
Envoyé le {(new Date(props.message.c_time)).toLocaleDateString("fr-FR")} à {(new Date(props.message.c_time)).toLocaleTimeString("fr-FR")}
</Typography>
</Fragment>
)
}
@@ -1,95 +0,0 @@
import React from 'react'
import { Typography } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import _ from "lodash"
const useStyles = makeStyles(theme => ({
userMessageLeft: {
display: 'flex',
alignItems: 'flex-end',
justifyContent: 'flex-start',
},
userMessageRight: {
display: 'flex',
alignItems: 'flex-end',
justifyContent: 'flex-end',
},
messageSender: {
fontSize: '0.9em',
fontWeight: '300',
color: theme.palette.primary.important,
},
messageContent: {
fontWeight: '300',
color: theme.palette.secondary.main,
},
userBubble: {
width: 'auto',
borderRadius: '5px',
padding: theme.spacing(2),
wordBreak: 'break-word',
},
userBubbleVideo: {
minWidth: '60vw',
[theme.breakpoints.up('sm')]: {
minWidth: '45vw',
},
[theme.breakpoints.up('md')]: {
minWidth: '30vw',
},
},
currentUserBubble: {
background: theme.palette.primary.main,
alignSelf: 'flex-end',
},
otherUserBubble: {
background: theme.palette.primary.important,
alignSelf: 'flex-start',
},
avatar: {
width: '2.5em',
height: '2.5em',
borderRadius: '50%',
margin: theme.spacing(0,1),
},
first: {
order: 1,
},
second: {
order: 2,
}
}));
export default function ChatCardMessage(props) {
const { side, firstname, lastname, picture, message, messageTexte, video, messageSenderClass, bubbleClass } = props;
const classes = useStyles();
const userBubble = (video) ? classes.userBubble +' '+ classes.userBubbleVideo : classes.userBubble
return (
<section className={(side==='left')? classes.userMessageLeft : classes.userMessageRight }>
{picture ?
<img alt="talents-tube" src={`http://recruteur.talentstube.com/uploads/img/${picture}`} className={(side==='left')? classes.first+' '+classes.avatar : classes.second +' '+classes.avatar} />
:
<img alt="talents-tube" src='/static/images/default/account-avatar-default.svg' className={(side==='left')? classes.first +' '+ classes.avatar : classes.second+' '+classes.avatar } />
}
<div className={(side==='left')? classes.second : classes.first}>
<Typography
className={classes.messageSender +' '+ messageSenderClass}
>
{firstname + ' ' + lastname}
</Typography>
<div className={userBubble + ' ' + bubbleClass}>
<Typography
className={classes.messageContent}
>
{message}
{messageTexte}
</Typography>
</div>
</div>
</section>
)
}
@@ -1,54 +0,0 @@
import React from "react";
import { Slide } from "@material-ui/core";
function getScrollY(scroller) {
return scroller.pageYOffset !== undefined
? scroller.pageYOffset
: scroller.scrollTop !== undefined
? scroller.scrollTop
: (document.documentElement || document.body.parentNode || document.body)
.scrollTop;
}
const useHideOnScroll = options => {
const { threshold, scroller } = options;
const scrollRef = React.useRef();
const [hide, setHide] = React.useState(false);
const handleScroll = React.useCallback(() => {
const scrollY = getScrollY(scroller || window);
const prevScrollY = scrollRef.current;
scrollRef.current = scrollY;
setHide(
scrollY < prevScrollY
? false
: scrollY > prevScrollY &&
scrollY > (threshold != null ? threshold : 100)
? true
: false
);
}, [scroller, threshold]);
React.useEffect(() => {
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, [handleScroll]);
return hide;
};
export default function HideOnScroll(props) {
const { children, threshold, scroller, ...other } = props;
const hide = useHideOnScroll({ threshold, scroller });
return (
<Slide appear={false} direction="down" in={!hide} {...other}>
{children}
</Slide>
);
}
+14 -46
View File
@@ -1,60 +1,29 @@
import React from 'react';
import React, { Fragment } from 'react';
import PropTypes from "prop-types";
import { withStyles } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';
import AssignmentIcon from '@material-ui/icons/Assignment';
import RoomIcon from '@material-ui/icons/Room';
import LocationOnIcon from '@material-ui/icons/LocationOn';
import BusinessCenterIcon from '@material-ui/icons/BusinessCenter';
import Business from '@material-ui/icons/Business';
import Typography from '@material-ui/core/Typography';
import WatchLater from '@material-ui/icons/WatchLater';
import Home from '@material-ui/icons/Home';
import People from '@material-ui/icons/People';
import Place from '@material-ui/icons/Place';
import SvgIcon from '@material-ui/core/SvgIcon';
const variantIcon = {
assignment: AssignmentIcon,
room: RoomIcon,
location_on: LocationOnIcon,
business_center: BusinessCenterIcon,
business: Business,
watch_later: WatchLater,
home: Home,
people: People,
place: Place,
};
const styles = theme => ({
root: {
alignItems: 'flex-start',
justifyContent: 'center',
marginLeft: theme.spacing(3),
marginRight: theme.spacing(3),
},
icon: {
fontSize: '1.1em',
},
text: {
fontSize: '0.9em',
fontWeight: '200',
card: {
display: 'flex',
position: 'relative',
height: '60vh',
width: '100%',
},
});
class IconText extends React.Component {
render() {
const { classes, variant, text } = this.props;
const Icon = variantIcon[variant];
return (
<Grid container className={classes.root}>
<Grid item xs={1}>
<Icon className={classes.icon} />
</Grid>
<Grid item xs={9}>
<Typography className={classes.text}>{text}</Typography>
</Grid>
</Grid>
<Fragment>
<SvgIcon>
<path d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z" />
</SvgIcon>
</Fragment>
);
}
}
@@ -62,7 +31,6 @@ class IconText extends React.Component {
IconText.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
text: PropTypes.string.isRequired,
};
export default withStyles(styles, { withTheme: true })(IconText);
-64
View File
@@ -1,64 +0,0 @@
import React from 'react';
import PropTypes from "prop-types";
import { withStyles } from '@material-ui/core/styles';
import AssignmentIcon from '@material-ui/icons/Assignment';
import RoomIcon from '@material-ui/icons/Room';
import LocationOnIcon from '@material-ui/icons/LocationOn';
import HomeOnIcon from '@material-ui/icons/Home';
import WatchLater from '@material-ui/icons/WatchLater';
import BusinessCenterIcon from '@material-ui/icons/BusinessCenter';
import People from '@material-ui/icons/People';
import Typography from '@material-ui/core/Typography';
import Business from '@material-ui/icons/Business';
import Place from '@material-ui/icons/Place';
const variantIcon = {
assignment: AssignmentIcon,
room: RoomIcon,
location_on: LocationOnIcon,
home: HomeOnIcon,
watch_later: WatchLater,
business_center: BusinessCenterIcon,
business: Business,
people: People,
place: Place,
};
const styles = theme => ({
root: {
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
marginRight: theme.spacing(1),
},
icon: {
fontSize: '1.1em',
},
text: {
fontSize: '0.9em',
fontWeight: '200',
},
});
class IconTextInline extends React.Component {
render() {
const { classes, variant, text } = this.props;
const Icon = variantIcon[variant];
return (
<section className={classes.root}>
<Icon className={classes.icon} />
<Typography className={classes.text}>{text}</Typography>
</section>
);
}
}
IconTextInline.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
text: PropTypes.string.isRequired,
};
export default withStyles(styles, { withTheme: true })(IconTextInline);
-39
View File
@@ -1,39 +0,0 @@
import React from 'react'
import { JobPostingJsonLd } from 'next-seo';
const JobPosting = props => {
return (
<JobPostingJsonLd
datePosted={props.job_date}
description={props.job_description}
hiringOrganization={{
name: props.job_brand,
sameAs: props.job_brand_link,
}}
jobLocation={{
addressLocality: props.job_ville,
addressRegion: props.job_dept,
// postalCode: props.job_location,
streetAddress: props.job_location,
addressCountry: props.job_pays,
}}
title={props.job_title}
validThrough={props.job_date_fin}
applicantLocationRequirements="FR"
employmentType = {props.job_contract_type + ","+props.job_temps_type }
/>
)
}
JobPosting.propTypes = {
// seo_title: PropTypes.string.isRequired,
// seo_description: PropTypes.string.isRequired,
// seo_url: PropTypes.string.isRequired,
// image: PropTypes.string.isRequired,
}
export default JobPosting
-113
View File
@@ -1,113 +0,0 @@
import React, { Component, Fragment } from 'react'
import { Snackbar } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles'
import IconButton from '@material-ui/core/IconButton';
import CloseIcon from '@material-ui/icons/Close';
const styles = theme => ({
close: {
padding: theme.spacing.unit / 2,
},
});
var EdeclicLib = null
class Messager extends Component {
state = {
openSnack: false,
title: '',
body: '',
link: '',
tokenStopListener: null,
messageStopListener: null,
}
constructor(props) {
super(props);
}
async componentDidMount() {
EdeclicLib = (await import('./firebase-client.js')).default
if (!EdeclicLib.messaging)
return
this.setState({ tokenStopListener: EdeclicLib.messaging.onTokenRefresh(this.RefreshToken) })
this.setState({ messageStopListener: EdeclicLib.messaging.onMessage(this.MessageReceiver) })
}
componentWillUnmount() {
if (process.browser) {
if (!EdeclicLib.messaging)
return
if (!!this.state.tokenStopListener)
this.state.tokenStopListener();
if (!!this.state.messageStopListener)
this.state.messageStopListener();
}
}
RefreshToken = () => {
EdeclicLib.messaging.getToken().then(function (refreshedToken) {
console.info('Token refreshed.');
// Indicate that the new Instance ID token has not yet been sent to the
// app server.
EdeclicLib.setTokenSentToServer(false);
// Send Instance ID token to app server.
EdeclicLib.sendTokenToServer(refreshedToken);
}).catch(function (err) {
console.warning('Unable to retrieve refreshed token ', err);
});
}
// Handle incoming messages. Called when:
// - a message is received while the app has focus
// - the user clicks on an app notification created by a service worker
// `messaging.setBackgroundMessageHandler` handler.
MessageReceiver = (payload) => {
console.info('Message received in Messager. ', payload);
this.setState({
openSnack: true,
title: payload.notification.title,
body: payload.notification.body,
link: payload.notification.click_action
});
}
handleClose = () => {
this.setState({ openSnack: false });
}
render() {
const { classes } = this.props;
return (
<Fragment>
<Snackbar
anchorOrigin={{
vertical: 'top',
horizontal: 'right',
}}
open={this.state.openSnack}
autoHideDuration={6000}
onClose={this.handleClose}
ContentProps={{
'aria-describedby': 'message-id',
}}
message={<span id="message-id">{this.state.title + " : " + this.state.body}</span>}
action={[
<a href={this.state.link}>Voir</a>,
<IconButton
key="close"
aria-label="Close"
color="inherit"
className={classes.close}
onClick={this.handleClose}
>
<CloseIcon />
</IconButton>,
]}
/>
</Fragment>
)
}
}
export default withStyles(styles)(Messager);
-36
View File
@@ -1,36 +0,0 @@
import React, { Fragment } from 'react';
import PropTypes from "prop-types";
import { withStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
const styles = theme => ({
container: {
padding: theme.spacing(0, 4),
},
text: {
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
fontSize: '1,2em',
fontWeight: '500',
color: theme.palette.primary.main,
textAlign: 'center',
},
});
function NoResult(props) {
const { classes } = props;
return (
<div className={ classes.container }>
<Typography className={ classes.text }>
{props.text}
</Typography>
</div>
);
}
NoResult.propTypes = {
classes: PropTypes.object.isRequired,
text: PropTypes.string.isRequired,
};
export default withStyles(styles)(NoResult)
-52
View File
@@ -1,52 +0,0 @@
import React from 'react'
import PropTypes from 'prop-types'
import Head from 'next/head'
const urlEnv = process.env.NODE_ENV;
const OgHead = props => {
return (
<Head>
<title key="title">{props.seo_title}</title>
<meta name="description" kenoindexy="description" content={props.seo_description} />
<meta name="keywords" content={props.seo_key}/>
<meta key="og:url" property="og:url" content={props.seo_url} />
<meta key="og:type" property="og:type" content="article" />
<meta key="og:title" property="og:title" content={props.seo_title} />
<meta property="fb:app_id" content="1800752833559014" data-react-helmet="true"></meta>
<meta
key="og:description"
property="og:description"
content={props.seo_description}
/>
<meta name="keywords" content={props.seo_key}/>
<meta key="og:image" property="og:image" content={props.image} />
<meta key="og:image:width" property="og:image:width" content="355" />
<meta key="og:image:height" property="og:image:height" content="200" />
<meta name="twitter:card" content="summary"/>
<meta name="twitter:site" content="@TalentsTube"/>
<meta name="twitter:title" content={props.seo_title}/>
<meta name="twitter:description" content={props.seo_description}/>
<meta name="twitter:image" content={props.image}/>
{/* A ENLEVER EN PROD */}
{/* <meta name="robots" content="noindex, nofollow"></meta> */}
{/* <meta httpEquiv='cache-control' content='no-store,no-cache'></meta>
<meta httpEquiv='expires' content='0'></meta>
<meta httpEquiv='pragma' content='no-cache'></meta> */}
<link rel="canonical" href={ props.seo_url} />
</Head>
)
}
OgHead.propTypes = {
// seo_title: PropTypes.string.isRequired,
// seo_description: PropTypes.string.isRequired,
// seo_url: PropTypes.string.isRequired,
// image: PropTypes.string.isRequired,
}
export default OgHead
-51
View File
@@ -1,51 +0,0 @@
import React, { Fragment } from 'react';
import PropTypes from "prop-types";
import { withStyles } from '@material-ui/core/styles';
const styles = theme => ({
root: {
display: 'flex',
flexDirection: 'column',
height: '100%',
},
start: {
alignItems: 'flex-start',
},
center: {
alignItems: 'center',
},
end: {
alignItems: 'flex-end',
},
});
class RootContainer extends React.Component {
render() {
const { classes, children, align } = this.props;
return (
<Fragment>
{(() => {
switch(align) {
case 'start':
return <section className={classes.root + ' ' + classes.start}>{children}</section>;
case 'center':
return <section className={classes.root + ' ' + classes.center}>{children}</section>;
case 'end':
return <section className={classes.root + ' ' + classes.end}>{children}</section>;
default:
return <section className={classes.root}>{children}</section>;
}
})()}
</Fragment>
);
}
}
RootContainer.propTypes = {
classes: PropTypes.object.isRequired,
}
export default withStyles(styles)(RootContainer);
-129
View File
@@ -1,129 +0,0 @@
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import clsx from 'clsx';
import Card from '@material-ui/core/Card';
import CardHeader from '@material-ui/core/CardHeader';
import CardMedia from '@material-ui/core/CardMedia';
import CardContent from '@material-ui/core/CardContent';
import CardActions from '@material-ui/core/CardActions';
import Collapse from '@material-ui/core/Collapse';
import Avatar from '@material-ui/core/Avatar';
import IconButton from '@material-ui/core/IconButton';
import Typography from '@material-ui/core/Typography';
import { red } from '@material-ui/core/colors';
import FavoriteIcon from '@material-ui/icons/Favorite';
import ShareIcon from '@material-ui/icons/Share';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import MoreVertIcon from '@material-ui/icons/MoreVert';
import withWidth, { isWidthUp } from '@material-ui/core/withWidth'
const useStyles = makeStyles(theme => ({
card: {
width: '100%',
},
media: {
height: 0,
paddingTop: '56.25%', // 16:9
},
expand: {
transform: 'rotate(0deg)',
transition: theme.transitions.create('transform', {
duration: theme.transitions.duration.shortest,
}),
width: '0.7em',
height: '0.7em',
fill: theme.palette.primary.dark,
},
expandOpen: {
transform: 'rotate(180deg)',
width: '0.7em',
height: '0.7em',
fill: theme.palette.primary.dark,
},
rootCard: {
boxShadow: 'none !important',
},
rootCardAction: {
margin: theme.spacing(1,0),
'& button': {
padding: theme.spacing(2,0),
borderRadius: 0,
}
},
rootCardContent: {
padding: 0 + '!important',
},
containerCollapse: {
position: 'relative',
'&:before': {
position: 'absolute',
bottom: 0,
height: '100%',
width: '100%',
content: '""',
background: 'linear-gradient(to top,rgba(255, 255, 255, 1) 8%, rgba(255, 255, 255, 0) 50%)',
pointerEvents: 'none',
},
},
containerCollapseDefault: {
position: 'relative',
'&:before': {
position: 'absolute',
bottom: 0,
height: '100%',
width: '100%',
content: '""',
background: ' rgba(255, 255, 255, 0)',
pointerEvents: 'none',
},
},
displayMore: {
color: theme.palette.primary.dark,
fontWeight: '600',
fontSize: '0.8rem',
},
}));
export default function SimpleCollapse(props) {
const classes = useStyles();
const [expanded, setExpanded] = React.useState(true);
function handleExpandClick() {
setExpanded(!expanded);
}
return (
<Card className={classes.card} classes={{ root: classes.rootCard }}>
<Collapse in={expanded} timeout="auto" collapsedHeight={isWidthUp('sm', props.width) ? '28vh' : '30vh'} className={clsx(classes.containerCollapse, {
[classes.containerCollapseDefault]: expanded,
})}>
<CardContent classes={{ root: classes.rootCardContent }}>
{props.children}
</CardContent>
</Collapse>
<CardActions disableSpacing classes={{ root: classes.rootCardAction }}>
<IconButton
onClick={handleExpandClick}
aria-expanded={expanded}
aria-label="Afficher plus "
> <Typography className={classes.displayMore}>
{(!expanded) ? 'Afficher plus' : 'Afficher moins'}
</Typography>
<ExpandMoreIcon className={clsx(classes.expand, {
[classes.expandOpen]: expanded,
})} />
</IconButton>
</CardActions>
</Card>
);
}
@@ -1,103 +0,0 @@
import React, { Fragment } from 'react';
import Link from 'next/link';
import clsx from 'clsx';
import { loadCSS } from 'fg-loadcss';
import { makeStyles } from '@material-ui/core/styles';
import { red } from '@material-ui/core/colors';
import Icon from '@material-ui/core/Icon';
import Button from '@material-ui/core/Button';
import ButtonGroup from '@material-ui/core/ButtonGroup';
const useStyles = makeStyles(theme => ({
icon: {
fontSize: '1em',
},
externalButton: {
'& .MuiButtonGroup-groupedContained': {
border: '0',
},
margin: theme.spacing(1,0),
margin: theme.spacing(1,1.2),
width: 'auto',
[theme.breakpoints.up('sm')]: {
minWidth: '20vw',
width: '50%',
marginLeft: 'auto',
marginRight: 'auto',
},
[theme.breakpoints.up('lg')]: {
width: '45%',
},
},
linkedinButton: {
backgroundColor: theme.palette.authSocial.linkedin,
padding: theme.spacing(1),
'&:hover': {
backgroundColor: theme.palette.authSocial.linkedin,
}
},
facebookButton: {
backgroundColor: theme.palette.authSocial.facebook,
padding: theme.spacing(1),
'&:hover': {
backgroundColor: theme.palette.authSocial.facebook,
}
},
linkedinIconButton: {
backgroundColor: theme.palette.authSocial.linkedinDark,
color: theme.palette.authSocial.linkedinDark,
border: 0,
},
facebookIconButton: {
backgroundColor: theme.palette.authSocial.facebookDark,
color: theme.palette.authSocial.facebookDark,
border: 0,
},
textButton: {
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-start',
width: '100%',
fontWeight: '400',
color: theme.palette.secondary.main,
textTransform: 'inherit',
[theme.breakpoints.up('sm')]: {
minWidth: '15vw',
},
},
}));
export default function SocialButtonsAuth(props) {
const classes = useStyles();
React.useEffect(() => {
loadCSS(
'https://use.fontawesome.com/releases/v5.1.0/css/all.css',
document.querySelector('#font-awesome-css'),
);
}, []);
return (
<Fragment>
<ButtonGroup variant="contained" onClick={props.linkedInAuth} className={classes.externalButton}>
<Button className={classes.linkedinIconButton}>
<Icon className={clsx(classes.icon, 'fab fa-linkedin-in')} color="secondary" />
</Button>
<Button className={classes.textButton +' '+ classes.linkedinButton+ ' cypLinkedInConnexion'} >
Connexion avec Linkedin
</Button>
</ButtonGroup>
<ButtonGroup variant="contained" onClick={props.facebookAuth} className={classes.externalButton}>
<Button className={classes.facebookIconButton}>
<Icon className={clsx(classes.icon, 'fab fa-facebook-f')} color="secondary" />
</Button>
<Button className={classes.textButton +' '+ classes.facebookButton} >
Connexion avec Facebook
</Button>
</ButtonGroup>
</Fragment>
);
}
-29
View File
@@ -1,29 +0,0 @@
'use strict';
export const payloadFromSubscription = function(subscription) {
var key = subscription.getKey ? subscription.getKey('p256dh') : '';
var auth = subscription.getKey ? subscription.getKey('auth') : '';
// NOTE: p256dg and auth are encoded into std base64, NOT urlsafe base64
return {
endpoint: subscription.endpoint,
keys: {
p256dh: key ? btoa(String.fromCharCode.apply(null, new Uint8Array(key))) : '',
auth: auth ? btoa(String.fromCharCode.apply(null, new Uint8Array(auth))) : ''
},
}
}
export const urlB64ToUint8Array= function(base64String) {
const padding = '='.repeat((4 - base64String.length % 4) % 4)
const base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/')
const rawData = window.atob(base64)
const outputArray = new Uint8Array(rawData.length)
for (let i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i)
}
return outputArray
}
-18
View File
@@ -1,18 +0,0 @@
function redirect(params) {
const { Router, ctx, location, status = 302 } = params
if (ctx.res) {
// Seems to be the version used by zeit
ctx.res.writeHead(status, {
Location: location,
// Add the content-type for SEO considerations
'Content-Type': 'text/html; charset=utf-8',
})
ctx.res.end()
return
}
Router.replace(location)
}
export default redirect
-87
View File
@@ -1,87 +0,0 @@
import React, { Fragment } from 'react'
import { Typography } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import _ from "lodash"
import Ar from "lodash/array"
const useStyles = makeStyles(theme => ({
video: {
display: 'flex',
flexDirection: 'column',
position: 'relative',
paddingBottom: '56%', /* 16:9 58%*/
'& iframe': {
position: 'absolute',
top: 0,
left: 'calc(50% - 50vw)',
width: '100vw',
height: '100%',
},
[theme.breakpoints.up('md')]: {
display: 'flex',
flexDirection: 'column',
position: 'relative',
paddingBottom: '36%', /* 16:9 */
'& iframe': {
position: 'absolute',
top: 0,
left: 'calc(50% - 32vw)',
width: '64vw',
height: '100%',
},
},
},
videoPresentation: {
display: 'flex',
flexDirection: 'column',
position: 'relative',
paddingBottom: '56%', /* 16:9 58%*/
'& iframe': {
position: 'absolute',
top: 0,
left: 'calc(50% - 50vw)',
width: '100vw',
height: '100%',
},
[theme.breakpoints.up('md')]: {
display: 'flex',
flexDirection: 'column',
position: 'relative',
paddingBottom: '56.5%', /* 16:9 */
'& iframe': {
position: 'absolute',
top: 0,
left: 'calc(50% - 32vw)',
width: '64vw',
height: '100%',
},
},
}
}));
export default function VideoVimeo(props) {
const {videoId, title, options, classesOverride, autoplay} = props;
const classes = useStyles();
let className = classes.video;
if (classesOverride) {
className = classes.videoPresentation;
}
return (
<section className={className +' '+classesOverride}>
<iframe className='player'
src={"https://player.vimeo.com/video/"+ videoId + options+"?texttrack=fr&autoplay="+autoplay}
frameBorder="0"
title={title}
webkitallowfullscreen="true" mozallowfullscreen="true" allowFullScreen></iframe>
</section>
)
}
VideoVimeo.defaultProps = {
options: "",
};
-177
View File
@@ -1,177 +0,0 @@
import React, { Component, Fragment } from 'react'
import PropTypes from 'prop-types'
import { connect } from "react-redux";
import { subscribeUserToPushRequest } from '../../actions/user'
import getConfig from 'next/config'
import { urlB64ToUint8Array, payloadFromSubscription } from './Utility'
var swRegistration = null
const WebPushContext = React.createContext()
function WebPushConsumer(props) {
return (
<WebPushContext.Consumer {...props}>
{context => {
if (!context) {
throw new Error(
`Webpush.Consumer cannot be rendered outside the Webpush component`,
)
}
return props.children(context)
}}
</WebPushContext.Consumer>
)
}
const { publicRuntimeConfig } = getConfig()
class WebPush extends Component {
static Consumer = WebPushConsumer;
state = {
on: false,
}
constructor(props) {
super(props)
}
componentDidMount() {
if (swRegistration === null) {
this.onRegisterServiceWorker()
}
}
UNSAFE_componentWillReceiveProps(nextProps) {
console.log("isUserSubscribedToPush ::: " + nextProps.isUserSubscribedToPush);
if (this.props.subscriveUserEnabled != nextProps.subscriveUserEnabled && nextProps.subscriveUserEnabled) {
this.onSubscribeUser()
}
if (!!nextProps.isUserSubscribedToPush) {
this.setState({ on: true })
}
}
onUpdateSubscriptionOnServer = (subscription) => {
console.log("onUpdateSubscriptionOnServer:", subscription)
var payload = payloadFromSubscription(subscription)
console.log("payload:", JSON.stringify(payload))
this.setState({ subscription: subscription })
this.props.subscribeUserToPushRequest(payload);
this.setState(({ on }) => ({ on: !on }))
}
onSubscriptionFailed = (error) => {
console.log("onSubscriptionFailed:", error)
this.setState(({ on }) => ({ on: false }))
}
toggleSubscription = () => {
console.log(this.state.on)
if (!this.state.on) {
this.onSubscribeUser()
}
else {
this.onUnSubscribeUser()
}
}
onSubscribeUser = () => {
if (swRegistration == null) {
return
}
swRegistration.pushManager.getSubscription()
.then((subscription) => {
var isSubscribed = !(subscription === null)
if (isSubscribed) {
this.onUpdateSubscriptionOnServer(subscription)
} else {
const applicationServerKey = urlB64ToUint8Array(publicRuntimeConfig.applicationServerPublicKey)
swRegistration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerKey
})
.then((subscription) => {
console.log('User is subscribed.')
if (this.onUpdateSubscriptionOnServer) {
this.onUpdateSubscriptionOnServer(subscription)
}
})
.catch((err) => {
console.log('Failed to subscribe the user: ', err)
if (onSubscribeFailed) {
this.onSubscriptionFailed(err)
}
});
}
})
}
onUnSubscribeUser = () => {
swRegistration.pushManager.getSubscription()
.then((subscription) => {
if (subscription) {
return subscription.unsubscribe();
}
})
.then(() =>
this.setState(({ on }) => ({ on: false })))
//TODO: facultatif update DB
// .then(() => {
// return fetch(//, {
// method: 'POST',
// headers: {
// 'Content-Type': 'application/json'
// },
// body: JSON.stringify(subscription)
// })
// .then((response) => {
// if (!response.ok) {
// throw new Error('Bad status code from server.');
// }
// ///TODO bind UI
// return true;
// })
// })
.catch((err) => {
console.error('Failed to unsubscribe the user.', err);
});
}
onRegisterServiceWorker = () => {
navigator.serviceWorker.register('/static/js/Edeclic-service-worker.js')
.then(function (swReg) {
console.info('Service Worker is registered', swReg);
swRegistration = swReg;
})
}
render() {
return (<WebPushContext.Provider
value={{ on: this.state.on, toggleSubscription: this.toggleSubscription }}
{...this.props}
/>)
}
}
WebPush.propTypes = {
}
function mapStateToProps(state) {
return {
isUserSubscribedToPush: state.user.isUserSubscribedToPush
};
}
export default connect(mapStateToProps, { subscribeUserToPushRequest })(WebPush);
-138
View File
@@ -1,138 +0,0 @@
//var firebase = require("firebase");
import firebase from "firebase/app"
import 'firebase/database'
import 'firebase/messaging'
//based on
//https://stackoverflow.com/questions/1479319/simplest-cleanest-way-to-implement-singleton-in-javascript
class Singleton {
// Properties & Methods
messaging;
fcmToken;
constructor() {
console.log('firebase-client constructor')
if (!Singleton.instance) {
Singleton.instance = this
}
// Initialize object
if (!firebase.messaging.isSupported()) {
console.log('firebase.messaging not supported')
return;
}
let config = {
apiKey: "AIzaSyArZab_4hUDgksQ4Dqdwv970JyRSlbGaKY",
authDomain: "edeclicpwa.firebaseapp.com",
databaseURL: "https://edeclicpwa.firebaseio.com",
projectId: "edeclicpwa",
storageBucket: "edeclicpwa.appspot.com",
messagingSenderId: "130215947970"
}
firebase.initializeApp(config);
navigator.serviceWorker
.register('/service-worker.js')
.then((registration) => {
firebase.messaging().useServiceWorker(registration);
});
this.messaging = firebase.messaging();
this.messaging.usePublicVapidKey('BEiMSVYvblP5oKcIY7b90r-5xLk1QYDra1sSdZHdaynihcb3Hx9wdZdI9IUHmbqureB_-IpOFKpm7arBB93J3rk');
console.log('FireBase Singleton Initialized')
return Singleton.instance
}
isSupported() {
this.messaging.app.firebase_.messaging.isSupported()
}
async requestPermission() {
console.log('Requesting permission...');
return this.messaging.requestPermission().then(function () {
console.log('Notification permission granted.');
return true
}).catch(function (err) {
console.log('Unable to get permission to notify.', err);
return false
});
}
async askForToken() {
var res = await this.messaging.getToken().then(async (currentToken) => {
if (currentToken) {
console.log(currentToken)
// this.fcmToken = currentToken;
await this.sendTokenToServer(currentToken);
return currentToken;
}
else {
// Show permission request.
console.log('No Instance ID token available. Request permission to generate one.');
let hasPerm = await this.requestPermission()
if (hasPerm)
{
debugger;
return await this.askForToken()
}
else
await this.setTokenSentToServer(false);
}
}).catch(async (err) => {
console.log('An error occurred while retrieving token. ', err);
// showToken('Error retrieving Instance ID token. ', err);
await this.setTokenSentToServer(false);
})
console.log("Token : ")
console.log(res);
return res
}
async deleteToken() {
// Delete Instance ID token.
// [START delete_token]
this.messaging.getToken().then(async (currentToken) => {
this.messaging.deleteToken(currentToken).then(async () => {
console.log('Token deleted.');
await this.setTokenSentToServer(false);
// [START_EXCLUDE]
// Once token is deleted update UI.
//resetUI();
// [END_EXCLUDE]
}).catch((err) => {
console.log('Unable to delete token. ', err);
});
// [END delete_token]
}).catch((err) => {
console.log('Error retrieving Instance ID token. ', err);
//showToken('Error retrieving Instance ID token. ', err);
});
}
async sendTokenToServer(currentToken) {
var tokenSent = await this.isTokenSentToServer()
if (!tokenSent) {
console.log('Sending token to server...');
firebase.database().ref('subscription/' + currentToken).set({
general: true
});
this.setTokenSentToServer(true);
} else {
console.log('Token already sent to server so won\'t send it again ' +
'unless it changes');
}
}
async isTokenSentToServer() {
return window.localStorage.getItem('sentToServer') === '1';
}
async setTokenSentToServer(sent) {
window.localStorage.setItem('sentToServer', sent ? '1' : '0');
}
}
const instance = new Singleton()
Object.freeze(instance)
export default instance
-106
View File
@@ -1,106 +0,0 @@
import Snackbar from '@material-ui/core/Snackbar';
import SnackbarContent from '@material-ui/core/SnackbarContent';
import React, { Component } from 'react';
import IconButton from '@material-ui/core/IconButton';
import ErrorIcon from '@material-ui/icons/Error';
import InfoIcon from '@material-ui/icons/Info';
import CloseIcon from '@material-ui/icons/Close';
import CheckCircleIcon from '@material-ui/icons/CheckCircle';
import WarningIcon from '@material-ui/icons/Warning';
import { makeStyles } from '@material-ui/core/styles';
import clsx from 'clsx';
import { amber, green } from '@material-ui/core/colors';
import { withStyles } from '@material-ui/core/styles';
const useStyles1 = makeStyles(theme => ({
success: {
backgroundColor: green[600],
},
error: {
backgroundColor: theme.palette.error.dark,
},
info: {
backgroundColor: theme.palette.primary.main,
},
warning: {
backgroundColor: amber[700],
},
icon: {
fontSize: 20,
},
iconVariant: {
opacity: 0.9,
marginRight: theme.spacing(1),
},
message: {
display: 'flex',
alignItems: 'center',
},
}));
const variantIcon = {
success: CheckCircleIcon,
warning: WarningIcon,
error: ErrorIcon,
info: InfoIcon,
};
function MySnackbarContentWrapper(props) {
const classes = useStyles1();
const { className, message, onClose, variant, ...other } = props;
const Icon = variantIcon[variant];
return (
<SnackbarContent
className={clsx(classes[variant], className)}
aria-describedby="client-snackbar"
message={
<span id="client-snackbar" className={classes.message}>
<Icon className={clsx(classes.icon, classes.iconVariant)} />
{message}
</span>
}
action={[
<IconButton key="close" aria-label="Close" color="inherit" onClick={onClose}>
<CloseIcon className={classes.icon} />
</IconButton>,
]}
{...other}
/>
);
}
const styles = theme => ({
container: {
display: 'flex',
flexDirection: 'column',
height: '100%',
},
});
class Snack extends Component {
render() {
return (
<Snackbar
anchorOrigin={{
vertical: 'bottom',
horizontal: 'right',
}}
open={this.props.openSnack}
autoHideDuration={7000}
>
<MySnackbarContentWrapper
variant={this.props.variant}
message={this.props.message}
onClose={this.props.onClose} />
</Snackbar>
)
}
}
export default withStyles(styles)(Snack);
+7 -162
View File
@@ -3,185 +3,30 @@ import red from '@material-ui/core/colors/red';
// Create a theme instance.
const theme = createMuiTheme({
// COLORS
palette: {
primary: {
main: '#1689FB',
darkMain: '#155EE4',
dark: '#1E2327',
important: '#25D89A',
conditional: '#D2D3D3',
main: '#155EE4',
},
secondary: {
main: '#FFFFFF',
dark: '#BBBCBD',
important: '#FF5A5F',
text: '#787B7D',
main: '#19857b',
},
flash: {
main: '#25D89A',
},
error: {
main: red.A400,
},
offerlistitem: {
title: '#1E2327',
icon: '#1E2327',
text: '#1E2327',
},
answer: {
main: '#E8E8E8',
},
background: {
default: '#ffffff',
grid: '#FCFCFC',
dark: '#1E2327',
grey: '#F3F9FF',
videotheque: '#54D7E6',
blog: '#1689FB',
recruteur: '#1E2327',
default: '#fff',
},
menu: {
darkText: '#1E2327',
lightText: '#F3F9FF',
darkDivider: '#32383C',
lightDivider: '#E2E2E2',
backArrow: 'rgba(30, 35, 39, 0.4)',
emailText: '#E8E8E9'
},
tags: {
main: '#E7F3FF',
},
input: {
main: '#F0F0F0',
},
authSocial: {
facebook: '#3064B7',
facebookDark: '#2C59A0',
linkedin: '#0276B5',
linkedinDark: '#025C8D',
},
social: {
facebook: '#334F8D',
twitter: '#1A97F0',
linkedin: '#006CAC',
mail: '#BBBCBD',
}
},
//OVERRIDE
overrides: {
MuiDrawer: {
paperAnchorLeft: {
right: '25%',
backgroundColor: '#1E2327',
},
paperAnchorRight: {
left: '25%',
backgroundColor: '#1E2327',
}
},
MuiAppBar: {
colorPrimary: {
color: '#1689FB',
backgroundColor: '#FFFFFF',
},
colorDefault: {
boxShadow: 'none',
backgroundColor: '#F8FBFF',
}
},
MuiPaper: {
elevation1: {
boxShadow: '0px 6px 16px rgba(30, 35, 39, 0.15)',
transition: 'box-shadow 2s',
'&:hover': {
boxShadow: '0px 6px 16px rgba(35, 40, 45, 0.25)',
transition: 'box-shadow 1.2s',
}
},
elevation4: {
transition: 'box-shadow .25s',
boxShadow: '0px 6px 16px rgba(30, 35, 39, 0.15)',
boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1px rgba(0, 0, 0, 0.2)',
},
},
MuiButton: {
root: {
'&:hover': {
backgroundColor: 'none',
},
'&:active': {
boxShadow: '0px',
},
},
contained: {
boxShadow: '0px',
'&:hover': {
backgroundColor: 'none',
},
'&:active': {
boxShadow: '0px',
},
},
outlined: {
border: '2px solid',
'&:hover': {
backgroundColor: 'none',
},
'&:active': {
boxShadow: '0px',
},
},
outlinedPrimary: {
border: '2px solid',
borderColor: '#1689FB',
'&:hover': {
border: '2px solid',
},
},
outlinedSecondary: {
border: '2px solid',
borderColor: '#FFFFFF',
'&:hover': {
border: '2px solid',
},
}
},
MuiButtonGroup: {
contained: {
boxShadow: 'inherit',
},
},
MuiLink: {
underlineHover: {
'&:hover': {
textDecoration: 'none',
},
}
},
MuiCheckbox: {
colorSecondary: {
'&.Mui-checked': {
color: "#1689FB",
}
}
},
MuiFilledInput: {
underline: {
'&:before, &:after': {
display: 'none',
},
}
},
},
});
File diff suppressed because it is too large Load Diff
@@ -1,427 +0,0 @@
import React, {Fragment} from 'react'
import {connect} from "react-redux";
import {makeStyles} from '@material-ui/styles';
import KeyboardArrowRightIcon from '@material-ui/icons/KeyboardArrowRight';
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
import {Button, Typography} from '@material-ui/core';
import dynamic from 'next/dynamic'
import {withStyles} from '@material-ui/core/styles'
import {uploadMediaPres} from '../../actions/media'
import {errorMessageSelector} from '../../reducers/media'
import {fetchCompanyRequest} from '../../actions/companies'
import {fetchCurrentUserRequest} from '../../actions/user'
import VideoVimeo from '../atoms/VideoVimeo'
import Router from 'next/router'
import LoaderVideo from '../templates/loaderVideo'
import Ar from "lodash/array"
import Snackbar from '@material-ui/core/Snackbar';
import { Alert, AlertTitle } from '@material-ui/lab';
import ReactHtmlParser, { processNodes, convertNodeToElement, htmlparser2 } from 'react-html-parser';
import Grid from '@material-ui/core/Grid';
import Container from '@material-ui/core/Container';
import Hidden from '@material-ui/core/Hidden';
import Movie from '@material-ui/icons/Movie';
const styles = theme => ({
container: {
width: '100%',
},
root: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'flex-start',
margin: theme.spacing(1),
flexWrap: 'wrap',
overflow: 'hidden',
backgroundColor: theme.palette.background.paper,
},
recorderContainer: {
//display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '100%'
},
rootButton: {
textTransform: 'inherit'
},
underlined: {
textDecoration: 'underline'
},
textButton: {
fontWeight: '700',
fontSize: '1.15em',
paddingLeft: theme.spacing(2)
},
videoPresentation: {
width: "100%",
height: "100%"
},
conseilButton: {
color: "#1e2327",
backgroundColor: "#fff",
padding: theme.spacing(3, 2),
margin: theme.spacing(1),
width: "100%",
textAlign: "right",
boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1' +
'px rgba(0, 0, 0, 0.14)',
'&:hover': {
color: "#1e2327",
backgroundColor: "#fff",
}
},
captureButton: {
width:"100%",
color: theme.palette.secondary.main,
backgroundColor: theme.palette.primary.main,
padding: theme.spacing(5, 2),
margin: theme.spacing(1),
boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 4px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1px rgba(0, 0, 0, 0.14)',
'&:hover': {
backgroundColor: theme.palette.primary.main,
},
},
importButton: {
color: "#1e2327",
backgroundColor: "#fff",
padding: theme.spacing(3, 2),
margin: theme.spacing(1),
width: "100%",
textAlign: "right",
boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1' +
'px rgba(0, 0, 0, 0.14)',
'&:hover': {
color: "#1e2327",
backgroundColor: "#fff",
}
},
InputKeyboardArrowDownIconBlank: {
fontSize: '2.5em',
color: "#ffffff",
textAlign: "right"
},
InputKeyboardArrowDownIcon: {
fontSize: '2.5em',
color: "#1e2327",
textAlign: "right"
},
buttons :{
display: "inline-table",
},
grille :{
paddingTop:theme.spacing(4),
width: "100%",
marginBottom:"30px",
borderRadius: "5px",
border: "1px solid #1E2327",
color:theme.palette.primary.dark
},
});
const Recorder = dynamic(() => import ('../organisms/Recorder'), {ssr: false})
class Etape2 extends React.Component {
state = {
loading: true,
activeStep: 0,
data: {},
openSnack: false,
errors: {},
success : {},
openStudio : false
};
componentDidMount() {
localStorage.setItem('loginRedirect', window.location.pathname)
if (!!!localStorage.getItem('ttJWT')) {
Router.push("/Login")
} else
this.setState({loading: false, firstname: this.props.user.firstname, videoPres: this.props.user.videoPres, video: this.props.user.presentation_video_id})
}
UNSAFE_componentWillReceiveProps(nextProps) {
this.setState({
loading: nextProps.loading,
openSnack: !!!_.isEmpty(nextProps.errors),
errors: !!!nextProps.errors
? {
errors: {
message: ""
}
}
: nextProps.errors,
videoPres: nextProps.videoPres,
video: nextProps.video
})
//window.location.reload(false);
if (nextProps.media.statusPres === 'success') {
const success = {};
success.message ="Profil mise à jour.";
this.setState({ success });
this.setActiveStep(1);
}
}
setActiveStep = (step) => {
this.setState({activeStep: step})
}
inputFilesystemChangePres = (e) => {
this.uploadMediaPres(e)
}
inputCamRecorderChange = (e) => {
this.uploadMediaPres(e)
}
uploadMediaPres = (e) => {
var file = e.target.files[0]
console.log ("envoi de video pres")
const data = new FormData()
data.append('upload', file)
//this.setState({ videoPres: videoPres })
console.log("VIDEO PRES OK");
this
.props
.uploadMediaPres(data);
}
AfficherSuccess() {
if (!this.state.success || !this.state.success.message) {
} else if (this.state.success.length != 0 && this.state.success.message != "") {
return (
<Snackbar open={open} autoHideDuration={1000} onClose={() => this.setState({open: false})}>
<Alert onClose={() => this.setState({open: false})} severity="success">
{ReactHtmlParser(this.state.success.message)}
</Alert>
</Snackbar>
);
}
return "";
}
handleClose = (event, reason) => {
this.setState({openSnack: false});
}
realise =() =>{
console.log("realise");
this.setState({ openStudio: true});
}
retour =() =>{
console.log("retour");
this.setState({ openStudio: false});
}
render() {
const {classes, company} = this.props;
const {loading, activeStep} = this.state;
let video;
if (this.state.videoPres) {
video = <VideoVimeo videoId={Ar.last(_.split(this.state.videoPres, '/'))} autoplay='1' classesOverride="videoPresentation"/>;
} else {
video = "";
}
if (typeof global.navigator === 'undefined') global.navigator = {};
if (typeof global.maps === 'undefined') global.maps = {};
return (
<Grid
container
direction="row"
justify="space-between"
alignItems="flex-start"
className={classes.grille}
justify="center"
alignItems="center">
<Grid item lg={12} md={12} xl={12} xs={12} >
<div id="video">
<Typography
align="center"
gutterBottom
variant="headline"
variant="h6"
component="h2"
className={classes.h6}>
<Movie className={classes.menuIcon}></Movie> Vidéo de présentation
</Typography>
<Typography
align="center">Donnez envie au recruteur de vous rencontrer grâce à la vidéo !</Typography>
</div>
<Fragment>
{this.AfficherSuccess()}
{ loading ? <LoaderVideo textePrincipal="Votre vidéo est en cours denvoi..." texteSecondaire="Veuillez rester sur la page pendant le chargement qui peut durer plusieurs minutes."/> : <div></div> }
<div className={classes.root}>
<Hidden xsUp>
&nbsp;
</Hidden>
<Container maxWidth="md">
<Grid container
justify="center"
alignItems="center"
spacing={2}
className={classes.buttons}>
<Grid item xs={12} sm={12} md={12} lg={12} xl={12}>
{ /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ?
(
<Fragment >
<input
type="file" accept="video/*" capture="camcorder"
className={classes.input}
style={{ display: 'none' }}
id="record-button-file"
multiple
onChange={this.inputCamRecorderChange}
/>
<label htmlFor="record-button-file">
<Button component="span" className={classes.captureButton} classes={{ root: classes.rootButton }}>
<img alt="talents-tube" src='/static/images/capture.svg' className={classes.iconButton} />
<Typography align="left" className={classes.textButton}>
Je <span className={classes.underlined}>réalise</span> ma vidéo de présentation
</Typography>
<KeyboardArrowRightIcon className={ classes.InputKeyboardArrowRightIcon }/>
</Button>
</label>
</Fragment>
):
(
<Fragment>
{this.state.openStudio == false ?
<Button component="span" className={classes.captureButton} classes={{ root: classes.rootButton }} onClick={this.realise}>
<img alt="talents-tube" src='/statique/images/capture.svg' className={classes.iconButton} />
<Typography align="left" className={classes.textButton}>
Je <span className={classes.underlined}>réalise</span> ma vidéo de présentation
</Typography>
<KeyboardArrowRightIcon className={ classes.InputKeyboardArrowRightIcon }/>
</Button>
:
<div className={classes.recorderContainer}>
<Button onClick={this.retour}>Retour au menu</Button>
<Recorder uploader={this.props.uploadMediaPres} titreBouton="Remplacer ma vidéo" retour="home" />
</div>
}
</Fragment>
)
}
</Grid>
<Grid item xs={12} sm={12} md={12} lg={12} xl={12}>
<div>
<input
type="file"
accept="video/*"
className={classes.input + ' cypButtonImportVid'}
style={{display: 'none'}}
id="import-button-file-pres"
onChange={this.inputFilesystemChangePres}/>
<label htmlFor="import-button-file-pres">
<Button
component="span"
className={classes.importButton}
classes={{
root: classes.rootButton}}>
<img
alt="talents-tube"
src='/statique/images/Import.svg'
className={classes.iconButton}/>
<Typography align="left" className={classes.textButton}>
J'<span className={classes.underlined}>importe</span> ma vidéo de présentation
</Typography>
<KeyboardArrowDownIcon className={classes.InputKeyboardArrowDownIcon}/>
</Button>
</label>
</div>
<div>
<label htmlFor="import-conseil">
<Button
component="span"
className={classes.importButton}
classes={{
root: classes.rootButton}}
onClick={() => Router.push(`/Conseils`)}>
<img
alt="talents-tube"
src='/statique/images/comment-faire-une-video-reponse.svg'
className={classes.iconButton}/>
<Typography align="left" className={classes.textButton}>
<span className={classes.underlined}>Comment</span> créer ma vidéo de présentation
</Typography>
<KeyboardArrowDownIcon className={classes.InputKeyboardArrowDownIcon}/>
</Button>
</label>
</div>
</Grid>
<Hidden xsUp>
&nbsp;
</Hidden>
<Grid item xs={12} sm={12} md={12} lg={12} xl={12}>
<div className={classes.videoPresentation}>
{video}
</div>
</Grid>
</Grid>
</Container>
</div>
{/* <div className={classes.textContainer}>
</div> */}
</Fragment>
</Grid>
</Grid>
);
}
}
Etape2.getInitialProps = function (context) {
const {companyId} = context.query
const {res} = context
//TODO :really needed ?
context
.store
.dispatch(fetchCurrentUserRequest())
if (!!companyId)
context.store.dispatch(fetchCompanyRequest(companyId))
return {}; //leave this please
}
function mapStateToProps(state) {
return {
loading: !!state.media.loading,
media: state.media,
offre: state.ad,
//errors: errorMessageSelector(state),
user: state.user,
company: state.company
};
}
export default withStyles(styles)(connect(mapStateToProps, {fetchCurrentUserRequest, fetchCompanyRequest, uploadMediaPres})(Etape2));
@@ -1,330 +0,0 @@
import React, { Fragment } from 'react';
import { connect } from "react-redux";
import { fetchCurrentUserRequest } from '../../actions/user'
import { fetchCompanyRequest } from '../../actions/companies'
import { uploadMediaCv } from '../../actions/mediaCv'
import { withStyles } from '@material-ui/core/styles'
import { makeStyles } from '@material-ui/styles';
import { Button, Typography, Divider, Hidden } from '@material-ui/core';
import KeyboardArrowRightIcon from '@material-ui/icons/KeyboardArrowRight';
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
import LoaderVideo from '../../components/templates/loaderVideo'
import Snack from '../../components/atoms/snack';
import Snackbar from '@material-ui/core/Snackbar';
import { Alert, AlertTitle } from '@material-ui/lab';
import ReactHtmlParser from 'react-html-parser';
import getConfig from 'next/config'
import Card from '@material-ui/core/Card';
import CardActions from '@material-ui/core/CardActions';
import CardContent from '@material-ui/core/CardContent';
import Description from '@material-ui/icons/Description';
import Grid from '@material-ui/core/Grid';
import Container from '@material-ui/core/Container';
const styles = theme => ({
root: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'flex-start',
margin: theme.spacing(1),
},
rootButton: {
textTransform: 'inherit',
},
underlined: {
textDecoration: 'underline',
},
textButton: {
fontWeight: '700',
fontSize: '1.15em',
paddingLeft: theme.spacing(2),
},
InputKeyboardArrowDownIcon: {
fontSize: '2.5em',
color: theme.palette.primary.dark,
},
importButton: {
color: "#1e2327",
backgroundColor: "#fff",
padding: theme.spacing(3, 2),
margin: theme.spacing(1),
width: "100%",
textAlign: "right",
boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.14), 0 1px 18px 0 rgba(0, 0, 0, 0.12), 0 3px 5px -1' +
'px rgba(0, 0, 0, 0.14)',
'&:hover': {
color: "#1e2327",
backgroundColor: "#fff",
}
},
grille :{
paddingTop:theme.spacing(4),
paddingRight:"30px",
width: "100%",
marginBottom:"30px",
borderRadius: "5px",
border: "1px solid #1E2327",
color:theme.palette.primary.dark
},
grille2 :{
margin:'10px',
width: "100%",
marginBottom:"30px",
},
button: {
width:"200px",
textTransform: 'inherit',
margin: theme.spacing(0, 8),
padding: theme.spacing(1.2, 2),
[theme.breakpoints.up('sm')]: {
margin: 'auto',
},
},
boutonMobile:{
width:"200px",
textAlign :"center",
color: theme.palette.secondary.main,
backgroundColor: theme.palette.primary.important,
margin : "0px !important"
},
lien:{
textDecoration:'none',
color:'#fff'
},
centered:{
textAlign:"center"
}
});
const { publicRuntimeConfig } = getConfig();
class Etape3 extends React.Component {
state = {
loading: true,
openSnack: false,
cv:false,
errors: {},
success : {}
};
componentDidMount() {
localStorage.setItem('loginRedirect', window.location.pathname)
if(!!!localStorage.getItem('ttJWT'))
{
Router.push("/Login")
}
else
this.setState({
loading: false,
cvLink: this.props.user.cv
})
}
UNSAFE_componentWillReceiveProps(nextProps) {
this.setState({
cvLink: nextProps.cvLink,
loading: nextProps.loading,
openSnack: !!!_.isEmpty(nextProps.errors),
errors: !!!nextProps.errors ? { errors: { message: "" } } : nextProps.errors,
})
if (nextProps.mediaCv.statusCv === 'success') {
const success = {};
success.message ="Profil mis à jour";
console.log("CV mis à jour!!!")
if(nextProps.mediaCv) console.log(nextProps.mediaCv.message)
this.setState({ success });
}
}
inputFilesystemChangeCv = (e) => {
this.uploadMediaCv(e)
}
uploadMediaCv = (e) => {
var file = e.target.files[0]
const data = new FormData()
data.append('upload', file)
console.log ("envoi de cv")
this.props.uploadMediaCv(data)
}
AfficherSuccess() {
if (!this.state.success || !this.state.success.message) {
console.log("Erreur Upload CV");
return "";
} else if (this.state.success.length != 0 && this.state.success.message != "") {
return (
<Snackbar open={open} autoHideDuration={1000} onClose={() => this.setState({open: false})}>
<Alert onClose={() => this.setState({open: false})} severity="success">
{ReactHtmlParser(this.state.success.message)}
</Alert>
</Snackbar>
);
}
return "";
}
AfficherLienCv(classes) {
console.log("afficher lien");
if (this.state.cvLink !="") {
return (
<Fragment>
<Hidden>&nbsp;</Hidden>
<Hidden>&nbsp;</Hidden>
<Hidden>&nbsp;</Hidden>
<Hidden>&nbsp;</Hidden>
<Hidden>&nbsp;</Hidden>
<div className={classes.centered} >
<Typography >
<a href={publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.postedContentCv + this.state.cvLink}
target="_blank" className={classes.lien}
>
<Button
variant="contained"
className={classes.button + ' ' + classes.boutonMobile}
>Visualiser mon CV
</Button>
</a>
<br />
</Typography>
</div>
</Fragment>
);
}
return "";
}
render() {
const { classes, company } = this.props;
const { loading } = this.state;
return (
<Grid
container
direction="row"
alignItems="flex-start"
className={classes.grille}
justify="center"
alignItems="center">
<Grid item lg={12} md={12} xl={12} xs={12} className={classes.grilleGauche}>
<div id="cv">
<Typography
align="center"
gutterBottom
variant="headline"
variant="h6"
component="h2"
className={classes.h6}>
<Description className={classes.menuIcon}></Description> Curriculum vitae
</Typography>
<Typography
align="center">Importez votre CV pour permettre aux recruteurs den savoir plus sur vous.
.</Typography>
</div>
<Fragment>
{ loading ?
<LoaderVideo textePrincipal="Votre candidature vidéo est en cours denvoi..." texteSecondaire="Veuillez rester sur la page pendant le chargement qui peut durer plusieurs minutes."/> :
<Grid
container
spacing={4}
direction="row"
alignItems="flex-start"
className={classes.grille2}
justify="center"
alignItems="center">
<Grid item xs={12} sm={12} md={12} lg={12} xl={12}>
<Fragment>
{this.AfficherSuccess()}
<input
type="file"
accept=".doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document, .pdf, .odt"
className={classes.input+' cypButtonImportVid'}
style={{ display: 'none' }}
id="import-button-file-cv"
onChange={this.inputFilesystemChangeCv}
/>
<label htmlFor="import-button-file-cv">
<Button component="span" className={classes.importButton} classes={{ root: classes.rootButton }}>
<img alt="talents-tube" src='/statique/images/Import-cv-candidat.svg' className={classes.iconButton} />
<Typography className={classes.textButton}>
J'<span className={classes.underlined}>importe</span> mon CV
</Typography>
<KeyboardArrowDownIcon className={ classes. InputKeyboardArrowDownIcon }/>
</Button>
</label>
<Hidden>&nbsp;</Hidden>
{this.AfficherLienCv(classes)}
<Hidden>&nbsp;</Hidden>
<Hidden>&nbsp;</Hidden>
<Hidden>&nbsp;</Hidden>
</Fragment>
</Grid>
</Grid>
}
</Fragment>
</Grid>
</Grid>
);
}
}
Etape3.getInitialProps = function (context) {
const { adId, companyId } = context.query
const {res} = context
//TODO :really needed ?
context.store.dispatch(fetchCurrentUserRequest())
if(!!adId)
context.store.dispatch(fetchJobRequest(adId))
else if(!!companyId)
context.store.dispatch(fetchCompanyRequest(companyId))
return {};//leave this please
}
function mapStateToProps(state) {
// console.log("mapStateToProps")
// console.log(state.loading)
// console.log(state.user)
// console.log(state.media.message)
return {
user: state.user ,
cvLink : state.mediaCv.message,
loading: !!state.media.loading,
cv : true,
mediaCv: state.mediaCv,
//errors: errorMessageSelector(state),
user: state.user,
company: state.company
};
}
export default withStyles(styles)(connect(mapStateToProps, { fetchCurrentUserRequest, fetchCompanyRequest, uploadMediaCv })(Etape3));
@@ -1,325 +0,0 @@
import React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
// import AccountStep from "../../components/organisms/AccountStep";
import AccountEtape1 from '../organisms/AccountEtape1';
import AccountEtape2 from '../organisms/AccountEtape2';
import AccountEtape3 from '../organisms/AccountEtape3';
import {withStyles} from '@material-ui/core/styles';
// import Switch from '@material-ui/core/Switch';
import PhoneIcon from '@material-ui/icons/Phone';
import MailIcon from '@material-ui/icons/Mail';
import PublicIcon from '@material-ui/icons/Public';
import DuoIcon from '@material-ui/icons/Duo';
import LinkedInIcon from '@material-ui/icons/LinkedIn';
import Facebook from '@material-ui/icons/Facebook';
// import FormGroup from '@material-ui/core/FormGroup'; import FormControlLabel
// from '@material-ui/core/FormControlLabel'; import FormControl from
// '@material-ui/core/FormControl';
import {updateUserRequest, updateUserPictureRequest} from '../../actions/user'
import {makeStyles} from '@material-ui/styles';
import {connect} from 'react-redux'
import getConfig from 'next/config'
import BottomNavigation from '@material-ui/core/BottomNavigation';
// import BottomNavigationAction from
// '@material-ui/core/BottomNavigationAction';
import RefreshIcon from '@material-ui/icons/Refresh';
// import FavoriteIcon from '@material-ui/icons/Favorite'; import LocationOnIcon
// from '@material-ui/icons/LocationOn';
import Link from 'next/link'
import Box from '@material-ui/core/Box';
import Tabs from '@material-ui/core/Tabs';
import Tab from '@material-ui/core/Tab';
import {
Card,
CardActions,
CardContent,
Avatar,
Typography,
Divider,
Button,
LinearProgress,
Stepper,
Step,
StepLabel,
StepContent,
StepButton,
Paper,
Grid
} from '@material-ui/core';
const styles = theme => ({
container: {
width: '100%'
},
button: {
textTransform: 'inherit',
marginLeft: theme.spacing(8),
marginRight: theme.spacing(8),
padding: theme.spacing(1.2, 2),
color: theme.palette.secondary.main,
backgroundColor: theme.palette.primary.important
},
stickToBottom: {
width: '100%',
position: 'fixed',
bottom: 0
},
menu: {
backgroundColor: "#DAE8F2"
},
});
const useStyles = makeStyles(theme => ({
root: {},
details: {
display: 'flex'
},
avatar: {
marginLeft: 'auto',
height: 110,
width: 100,
flexShrink: 0,
flexGrow: 0
},
progress: {
marginTop: theme.spacing(2)
},
information: {
display: 'flex',
flexDirection: 'column',
backgroundColor: theme.palette.primary.main,
[
theme
.breakpoints
.up('md')
]: {
display: 'flex',
flexDirection: 'row',
alignItems: 'flex-start',
justifyContent: 'space-around',
backgroundColor: theme.palette.primary.main,
padding: theme.spacing(7, 7)
},
'& a': {
textDecoration: 'none'
}
},
texteBlanc: {
color: "#fff"
},
uploadButton: {
marginRight: theme.spacing(2)
},
button: {
marginTop: theme.spacing(1),
marginRight: theme.spacing(1)
},
actionsContainer: {
marginBottom: theme.spacing(2)
},
resetContainer: {
padding: theme.spacing(3)
},
conteneur:{
backgroundColor: "#f3f3f4",
}
}));
function getSteps() {
return ['Informations personnelles', 'Vidéo de présentation', 'Expériences professionnelles'];
}
function getStepContent(step) {
switch (step) {
case 0:
return <AccountEtape1 ></AccountEtape1>;
case 1:
return <AccountEtape2></AccountEtape2>;
case 2:
return <AccountEtape3></AccountEtape3>;
default:
return 'Unknown step';
}
}
const AccountProfile = props => {
const {
className,
user,
...rest
} = props;
const logoUrl = user.picture;
const classes = useStyles();
// const user = { name: 'Laurent Laniau', city: 'Questembert', country:
// 'France', timezone: '', avatar: '/images/avatars/avatar_11.png' };
const {publicRuntimeConfig} = getConfig()
const [activeStep,
setActiveStep] = React.useState(0);
const [completed,
setCompleted] = React.useState(new Set());
const [skipped,
setSkipped] = React.useState(new Set());
const [state,
setState] = React.useState({checkedA: true, checkedB: true});
const steps = getSteps();
const totalSteps = () => {
return getSteps().length;
};
const isStepOptional = (step) => {
return step === 4;
};
const handleSkip = () => {
if (!isStepOptional(activeStep)) {
// You probably want to guard against something like this it should never occur
// unless someone's actively trying to break something.
throw new Error("You can't skip a step that isn't optional.");
}
setActiveStep((prevActiveStep) => prevActiveStep + 1);
setSkipped((prevSkipped) => {
const newSkipped = new Set(prevSkipped.values());
newSkipped.add(activeStep);
return newSkipped;
});
};
const skippedSteps = () => {
return skipped.size;
};
const completedSteps = () => {
return completed.size;
};
const allStepsCompleted = () => {
return completedSteps() === totalSteps() - skippedSteps();
};
const isLastStep = () => {
return activeStep === totalSteps() - 1;
};
const handleNext = () => {
const newActiveStep = isLastStep() && !allStepsCompleted()
? // It's the last step, but not all steps have been completed
// find the first step that has been completed
steps.findIndex((step, i) => !completed.has(i))
: activeStep + 1;
setActiveStep(newActiveStep);
};
const handleBack = () => {
setActiveStep((prevActiveStep) => prevActiveStep - 1);
};
const handleStep = (step) => () => {
console.log("step");
console.log(step);
setActiveStep(step);
};
const handleComplete = () => {
const newCompleted = new Set(completed);
newCompleted.add(activeStep);
setCompleted(newCompleted);
/**
* Sigh... it would be much nicer to replace the following if conditional with
* `if (!this.allStepsComplete())` however state is not set when we do this,
* thus we have to resort to not being very DRY.
*/
if (completed.size !== totalSteps() - skippedSteps()) {
handleNext();
}
};
const handleReset = () => {
setActiveStep(0);
setCompleted(new Set());
setSkipped(new Set());
};
const isStepSkipped = (step) => {
return skipped.has(step);
};
const handleChange = (event, newValue) => {
};
function isStepComplete(step) {
return completed.has(step);
}
function refresh() {
document
.location
.reload(true);
console.log("refresh")
}
return (
<Grid
container
>
<Grid item lg={12} md={12} xl={12} xs={12} >
<div >
<Paper elevation={0} >
<Tabs
value={1}
onChange={handleChange}
indicatorColor="primary"
textColor="theme.palette.primary.dark"
centered
>
<Link href="/Candidatures"><Tab label="Mes candidatures" /></Link>
<Tab label="Mon profil" />
</Tabs>
</Paper>
</div>
</Grid>
<Grid item lg={3} md={3} xl={4} xs={12}>
</Grid>
<Grid item lg={6} md={6} xl={4} xs={12} >
<AccountEtape1 ></AccountEtape1>
<AccountEtape2 ></AccountEtape2>
<AccountEtape3 ></AccountEtape3>
</Grid>
<Grid item lg={3} md={3} xl={4} xs={12}>
</Grid>
</Grid>
);
};
AccountProfile.propTypes = {
className: PropTypes.string
};
function mapStateToProps(state, ownProps) {
return {
user: state.user,
loading: !!state.user.loading,
errors: state.user.errors || ownProps.errors
};
}
export default withStyles(styles)(connect(mapStateToProps, {updateUserRequest})(AccountProfile))
@@ -1,306 +0,0 @@
import React, {Fragment} from 'react';
import {Hidden} from '@material-ui/core';
import PropTypes from 'prop-types';
import clsx from 'clsx';
// import AccountStep from "../../components/organisms/AccountStep";
import AccountEtape1 from './AccountEtape1';
import AccountEtape2 from './AccountEtape2';
import AccountEtape3 from './AccountEtape3';
import {withStyles} from '@material-ui/core/styles';
// import Switch from '@material-ui/core/Switch';
import PhoneIcon from '@material-ui/icons/Phone';
import MailIcon from '@material-ui/icons/Mail';
import PublicIcon from '@material-ui/icons/Public';
import DuoIcon from '@material-ui/icons/Duo';
import LinkedInIcon from '@material-ui/icons/LinkedIn';
import Facebook from '@material-ui/icons/Facebook';
// import FormGroup from '@material-ui/core/FormGroup'; import FormControlLabel
// from '@material-ui/core/FormControlLabel'; import FormControl from
// '@material-ui/core/FormControl';
import {updateUserRequest, updateUserPictureRequest} from '../../actions/user'
import {makeStyles} from '@material-ui/styles';
import {connect} from 'react-redux'
import getConfig from 'next/config'
import Router from 'next/router'
import BottomNavigation from '@material-ui/core/BottomNavigation';
// import BottomNavigationAction from
// '@material-ui/core/BottomNavigationAction';
import RefreshIcon from '@material-ui/icons/Refresh';
// import FavoriteIcon from '@material-ui/icons/Favorite'; import LocationOnIcon
// from '@material-ui/icons/LocationOn';
import Box from '@material-ui/core/Box';
import {
Card,
CardActions,
CardContent,
Avatar,
Typography,
Divider,
Button,
LinearProgress,
Stepper,
Step,
StepLabel,
StepContent,
StepButton,
Paper,
Grid
} from '@material-ui/core';
const styles = theme => ({
container: {
width: '100%'
},
button: {
textTransform: 'inherit',
marginLeft: theme.spacing(8),
marginRight: theme.spacing(8),
padding: theme.spacing(1.2, 2),
color: theme.palette.secondary.main,
backgroundColor: theme.palette.primary.important
},
stickToBottom: {
width: '100%',
position: 'fixed',
bottom: 0
}
});
const useStyles = makeStyles(theme => ({
root: {},
details: {
display: 'flex'
},
avatar: {
marginLeft: 'auto',
height: 110,
width: 100,
flexShrink: 0,
flexGrow: 0
},
progress: {
marginTop: theme.spacing(2)
},
information: {
display: 'flex',
flexDirection: 'column',
backgroundColor: theme.palette.primary.main,
[
theme
.breakpoints
.up('md')
]: {
display: 'flex',
flexDirection: 'row',
alignItems: 'flex-start',
justifyContent: 'space-around',
backgroundColor: theme.palette.primary.main,
padding: theme.spacing(7, 7)
},
'& a': {
textDecoration: 'none'
}
},
texteBlanc: {
color: "#fff"
},
uploadButton: {
marginRight: theme.spacing(2)
},
button: {
marginTop: theme.spacing(1),
marginRight: theme.spacing(1)
},
actionsContainer: {
marginBottom: theme.spacing(2)
},
resetContainer: {
padding: theme.spacing(3)
},
iconButton:{
marginTop: "50px",
[theme.breakpoints.down('md')]: {
marginTop: "50px",
},
},
button: {
textTransform: 'inherit',
marginTop: theme.spacing(4),
marginBottom: theme.spacing(2),
padding: theme.spacing(1.2, 1),
borderRadius: '3px',
color: theme.palette.secondary.main,
backgroundColor: theme.palette.primary.important,
},
title:{
fontFamily: 'Roboto',
fontSize: '1.625em',
fontWeight: '600',
padding: theme.spacing(3, 0),
},
texteEtape:{
fontSize: '1em',
fontWeight: '300',
},
conteneur:{
width:'400px',
},
tabContainer:{
display: 'flex',
flexDirection: 'column',
alignItems:'center',
textAlign:'center',
align:'center',
alignSelf:'center',
},
}));
const AccountProfile = props => {
const {
className,
user,
...rest
} = props;
const logoUrl = user.picture;
const classes = useStyles();
// const user = { name: 'Laurent Laniau', city: 'Questembert', country:
// 'France', timezone: '', avatar: '/images/avatars/avatar_11.png' };
const {publicRuntimeConfig} = getConfig()
return (
<Fragment >
<div className={classes.tabContainer}>
<div className={classes.conteneur}>
<Typography gutterBottom align="center" >
<span className={classes.title}>
<img
alt="talents-tube"
src='/statique/images/inscription/candidature-video-envoyee.svg'
className={classes.iconButton}/>
</span>
</Typography>
<Typography gutterBottom align="center" >
<span className={classes.title}>Bravo !<br></br>
Votre candidature a été envoyée
</span>
</Typography>
<Typography gutterBottom align="center" className={classes.conteneur}>
<div className={classes.texteEtape}>
Pour suivre létat davancement de vos candidatures, rendez-vous sur votre espace <b>Mon compte</b>.
</div>
</Typography>
<Typography gutterBottom align="center" className={classes.text}>
<Button
variant="contained"
className={classes.button}
classes={{ root: classes.rootButton }}
onClick={() => Router.push('/Candidatures')}
>
Accéder à Mon compte
</Button>
</Typography>
{/* <section className={classes.bottomContainer}>
<Button
variant="contained"
className={classes.button}
classes={{ root: classes.rootButton }}
onClick={() => Router.push('/Login')}
>
Connexion
</Button>
</section> */}
</div>
</div>
</Fragment>
// <Grid
// container
// spacing={4}
// direction="row"
// justify="space-between"
// alignItems="flex-start">
// <Grid item lg={9} md={6} xl={8} xs={12}>
// <Fragment>
// <Hidden>&nbsp;</Hidden>
// <Hidden>&nbsp;</Hidden>
// <Card
// variant="outlined"
// style={{
// width: 420 + "px",
// textAlign:"center"
// }}>
// <CardActions></CardActions>
// <CardContent>
// <Typography>
// Tu n'as pas tout dit dans ta vidéo?<br/>
// Pour mettre toutes les chances de ton côté,
// <b> dépose ton CV old school (format pdf, word)!</b>
// </Typography>
// </CardContent>
// </Card>
// <Hidden>&nbsp;</Hidden>
// <Card
// variant="outlined"
// style={{
// width: 420 + "px",
// textAlign:"center"
// }}>
// <CardContent>
// <AccountEtape3></AccountEtape3>
// </CardContent>
// </Card>
// <Hidden>&nbsp;</Hidden>
// <Hidden>&nbsp;</Hidden>
// <Card
// variant="outlined"
// style={{
// width: 420 + "px",
// textAlign:"center"
// }}>
// <CardContent>
// <Button
// variant="contained"
// color="primary"
// onClick={() => Router.push(`/Candidatures`)}
// className={classes.button}>
// Voir mes candidatures
// </Button>
// </CardContent>
// </Card>
// </Fragment>
// </Grid>
// <Grid item lg={3} md={6} xl={4} xs={12}></Grid>
// </Grid>
);
};
AccountProfile.propTypes = {
className: PropTypes.string
};
function mapStateToProps(state, ownProps) {
return {
user: state.user,
loading: !!state.user.loading,
errors: state.user.errors || ownProps.errors
};
}
export default withStyles(styles)(connect(mapStateToProps, {updateUserRequest})(AccountProfile))
-147
View File
@@ -1,147 +0,0 @@
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import Stepper from '@material-ui/core/Stepper';
import Step from '@material-ui/core/Step';
import StepButton from '@material-ui/core/StepButton';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import AccountEtape1 from '../organisms/AccountEtape1';
import AccountEtape2 from '../organisms/AccountEtape2';
import AccountEtape3 from '../organisms/AccountEtape3';
const useStyles = makeStyles((theme) => ({
root: {
width: '100%',
},
button: {
marginRight: theme.spacing(1),
},
completed: {
display: 'inline-block',
},
instructions: {
marginTop: theme.spacing(1),
marginBottom: theme.spacing(1),
},
}));
function getSteps() {
return ['Informations personnelles', 'Vidéo de présentation', 'Expériences professionnelles'];
}
function getStepContent(step) {
switch (step) {
case 0:
return <AccountEtape1 ></AccountEtape1>;
case 1:
return <AccountEtape2></AccountEtape2>;
case 2:
return <AccountEtape3></AccountEtape3>;
default:
return 'Unknown step';
}
}
export default function HorizontalNonLinearStepper() {
const classes = useStyles();
const [activeStep, setActiveStep] = React.useState(0);
const [completed, setCompleted] = React.useState({});
const steps = getSteps();
const totalSteps = () => {
return steps.length;
};
const completedSteps = () => {
return Object.keys(completed).length;
};
const isLastStep = () => {
return activeStep === totalSteps() - 1;
};
const allStepsCompleted = () => {
return completedSteps() === totalSteps();
};
const handleNext = () => {
const newActiveStep =
isLastStep() && !allStepsCompleted()
? // It's the last step, but not all steps have been completed,
// find the first step that has been completed
steps.findIndex((step, i) => !(i in completed))
: activeStep + 1;
setActiveStep(newActiveStep);
};
const handleBack = () => {
setActiveStep((prevActiveStep) => prevActiveStep - 1);
};
const handleStep = (step) => () => {
setActiveStep(step);
};
const handleComplete = () => {
const newCompleted = completed;
newCompleted[activeStep] = true;
setCompleted(newCompleted);
handleNext();
};
const handleReset = () => {
setActiveStep(0);
setCompleted({});
};
return (
<div className={classes.root}>
<Stepper alternativeLabel nonLinear activeStep={activeStep}>
{steps.map((label, index) => (
<Step key={label}>
<StepButton onClick={handleStep(index)} completed={completed[index]}>
{label}
</StepButton>
</Step>
))}
</Stepper>
<div>
{allStepsCompleted() ? (
<div>
{/* <Typography className={classes.instructions}>
Toutes les étapes sont terminées -
</Typography>
<Button onClick={handleReset}>Annuler</Button> */}
</div>
) : (
<div>
<Typography className={classes.instructions}>{getStepContent(activeStep)}</Typography>
<div>
{/* <Button disabled={activeStep === 0} onClick={handleBack} className={classes.button}>
Précédent
</Button>
<Button
variant="contained"
color="primary"
onClick={handleNext}
className={classes.button}
>
Suivant
</Button> */}
{/* {activeStep !== steps.length &&
(completed[activeStep] ? (
<Typography variant="caption" className={classes.completed}>
Step {activeStep + 1} already completed
</Typography>
) : (
<Button variant="contained" color="primary" onClick={handleComplete}>
{completedSteps() === totalSteps() - 1 ? 'Etape valide' : 'Processus terminé'}
</Button>
))} */}
</div>
</div>
)}
</div>
</div>
);
}
@@ -1,42 +0,0 @@
import React, { useState } from 'react';
import clsx from 'clsx';
import PropTypes from 'prop-types';
import { makeStyles } from '@material-ui/styles';
import Link from 'next/link';
import ListItem from '@material-ui/core/ListItem';
import Box from '@material-ui/core/Box';
import {
Card,
CardHeader,
CardContent,
CardActions,
Divider,
Grid,
Button,
TextField
} from '@material-ui/core';
const useStyles = makeStyles(() => ({
root: {}
}));
const AccountVideoPres = props => {
const { className, ...rest } = props;
const classes = useStyles();
return (
<Card
{...rest}
className={clsx(classes.root, className)}
>
</Card>
);
};
AccountVideoPres.propTypes = {
className: PropTypes.string
};
export default AccountVideoPres;
-849
View File
@@ -1,849 +0,0 @@
import React, { Component, Fragment, useState } from 'react'
import { withStyles } from '@material-ui/core/styles';
import { Button, Typography, Divider, Hidden } from '@material-ui/core';
import TextField from '@material-ui/core/TextField';
import Input from '@material-ui/core/Input';
import { connect } from 'react-redux'
import { postAdAnswerRequest } from '../../actions/answer'
import { updateUserRequest, updateUserPictureRequest } from '../../actions/user'
import Avatar from '@material-ui/core/Avatar';
import KeyboardArrowRightIcon from '@material-ui/icons/KeyboardArrowRight';
import Loader from './../templates/loader'
import getConfig from 'next/config'
import 'video-react/dist/video-react.css';
import { Player } from 'video-react';
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
import GooglePlaceAutocomplete from 'mui-places-autocomplete'
import { geocodeByAddress } from 'react-places-autocomplete'
import FormControl from '@material-ui/core/FormControl'
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
import { uploadMediaCv } from '../../actions/mediaCv'
import GetApp from '@material-ui/icons/GetApp';
// import PlacesAutocomplete from 'react-places-autocomplete';
// import {
// geocodeByAddress,
// geocodeByPlaceId,
// getLatLng,
// } from 'react-places-autocomplete';
// import GoogleAutoComplete from 'react-google-autocomplete-address-fields';
const styles = theme => ({
container: {
width: '100%',
},
form: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
padding: '24px',
paddingBottom: theme.spacing(8),
marginBottom: theme.spacing(8),
'&>div': {
marginTop: theme.spacing(1.5),
marginBottom: theme.spacing(1.5),
},
[theme.breakpoints.up('md')]: {
padding: '0 calc(25vw + 24px)',
},
},
importContainer: {
alignSelf: 'flex-start',
},
textField: {
width: '100%',
'&:disabled': {
color: theme.palette.secondary.dark,
},
'& label': {
color: theme.palette.primary.dark,
},
'& fieldset:hover': {
borderColor: theme.palette.primary.main + ' !important',
},
},
foot: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
zIndex: '10',
width: '100%',
position: 'fixed',
bottom: 0,
padding: theme.spacing(1.2, 0),
backgroundColor: theme.palette.secondary.main,
boxShadow: '0px 0px 10px rgba(30, 35, 39, 0.10)',
},
rootButton: {
textTransform: 'inherit',
},
button: {
textTransform: 'inherit',
marginLeft: theme.spacing(8),
marginRight: theme.spacing(8),
padding: theme.spacing(1.2, 2),
color: theme.palette.secondary.main,
backgroundColor: theme.palette.primary.important,
},
containerImport:{
width:"100%",
textAlign:"left",
align:"left",
alignItems:"flex-start",
border: 0,
margin: 0,
display: "inline-flex",
padding: 0,
position: "relative",
flexDirection: "column",
verticalAlign: "top",
marginBottom:"20px !important"
},
importButton: {
padding: '4px 8px',
textTransform: 'inherit',
border: '2px solid #1E2327',
color: '#1E2327',
},
remplacerButton: {
color: '#1E2327',
borderColor: '#1E2327',
border: '2px solid',
padding: '9.6px 8px',
margin:'15px 0px 25px 0px',
textTransform: 'inherit',
},
popup: {
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
fontWeight: '400',
color: '#8E9092'
},
player:{
width:"100px"
},
labelGeoloc:{
paddingLeft:"14px",
fontSize: "0.8rem",
color:"#1E2327",
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
fontWeight: "400",
lineHeight: "1",
letterSpacing: "0.00938em", }
,conteneurGoogle:{
border:"1px solid rgb(200, 200, 200)",
borderRadius :"5px",
padding:"5px 0px",
},
conteneurGoogleComposant:{
paddingLeft:"14px"
}
});
export const getCountryFromAddress = (address) => {
if (!address) {
return '';
}
try {
const country = address.address_components.filter(component => component.types.includes('country')).map(c => c.long_name)[0];
console.log('using country for filter ' + country);
return country;
} catch (error) {
console.log(error);
return '';
}
}
const { publicRuntimeConfig } = getConfig()
//https://xd.adobe.com/view/ba98331a-9145-4d67-7e27-25a36e519ef4-cca9/screen/a96779d7-bdb3-410a-8f19-e6987acb98ee/Candidature-Step-3
class Answer extends Component {
constructor(props) {
super(props);
const viewValue = this.props.value;
this.onSuggestionSelected = this.onSuggestionSelected.bind(this);
this.onChange = this.onChange.bind(this);
}
state = {
file: null,
firstname: '',
lastname: '',
phone: '',
currentJob: '',
geoloc: '',
value:'',
route: '',
street_number: '',
locality: '',
administrative_area_level_2: '',
administrative_area_level_1: '',
country: '',
postal_code: '',
formatted_address:"",
lat:"",
lng:"",
linkedin: '',
twitter: '',
website: '',
mediaId: null,
mediaUrl: null,
thumbnails:null,
heure: null,
companyId: null,
address:'',
errorMessage:'',
open: false,
loading: true,
openSnack: false,
cv:false,
};
UNSAFE_componentWillReceiveProps(nextProps) {
this.setState({
firstname: this.state.firstname,
lastname: this.state.lastname,
phone: this.state.phone,
currentJob: this.state.currentJob,
geoloc: this.state.geoloc,
value: this.state.value,
route: this.state.route,
street_number: this.state.street_number,
locality: this.state.locality,
administrative_area_level_2: this.state.administrative_area_level_2,
administrative_area_level_1: this.state.administrative_area_level_1,
country: this.state.country,
postal_code: this.state.postal_code,
formatted_address : this.state.formatted_address,
lat:this.state.lat,
lng: this.state.lng,
linkedin: this.state.linkedin,
twitter: this.state.twitter,
website: this.state.website,
mediaId: nextProps.mediaId,
mediaUrl: nextProps.mediaUrl,
thumbnails: nextProps.thumbnails,
heure: nextProps.heure,
companyId: nextProps.companyId,
cvLink: nextProps.cvLink,
loading: nextProps.loading,
openSnack: !!!_.isEmpty(nextProps.errors),
})
if (nextProps.loading) {
const success = {};
success.message ="CV mis à jour";
console.log("CV mis à jour!!!")
this.setState({ success });
}
}
componentDidMount() {
console.log("ANSWER ! ");
console.log(this.props);
this.setState({
firstname: this.props.user.firstname,
lastname: this.props.user.lastname,
phone: this.props.user.phone,
currentJob: this.props.user.currentJob,
value: this.props.user.geoloc && this.props.user.geoloc[0].formatted_address ? this.props.user.geoloc[0].formatted_address :"",
geoloc: this.props.user.geoloc && this.props.user.geoloc[0].formatted_address ? this.props.user.geoloc[0].formatted_address :"",
route: "",
street_number: "",
locality: "",
administrative_area_level_2: "",
administrative_area_level_1: "",
country: "",
postal_code: "",
formatted_address:"",
lat:"",
lng:"",
linkedin: this.props.user.linkedin,
twitter: this.props.user.twitter,
website: this.props.user.website,
video: this.props.answer,
mediaUrl : this.props.mediaUrl,
thumbnails : this.props.thumbnails,
heure : this.props.heure,
loading: false,
cvLink: this.props.user.cv
})
console.log(this.state);
}
inputFilesystemChange = (e) => {
this.uploadMediaCv(e)
}
uploadMediaCv = (e) => {
var file = e.target.files[0]
const data = new FormData()
data.append('upload', file)
this.props.uploadMediaCv(data)
}
AfficherSuccess() {
if (!this.state.success || !this.state.success.message) {
console.log("Erreur Upload CV");
return "";
} else if (this.state.success.length != 0 && this.state.success.message != "") {
return (
<Snackbar open={open} autoHideDuration={1000} onClose={() => this.setState({open: false})}>
<Alert onClose={() => this.setState({open: false})} severity="success">
{ReactHtmlParser(this.state.success.message)}
</Alert>
</Snackbar>
);
}
return "";
}
AfficherLienCv() {
console.log("afficher lien");
if (this.state.cvLink !="") {
return (
<Fragment>
<Typography >
<a href={publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.postedContentCv + this.state.cvLink}
target="_blank"
style={{
color:'#1E2327',
'&:hover': {
color: '#1E2327',
},
backgroundColor: '#F3F3F4',
width:'100%',
fontWeight: '500',
fontSize: '1em',
padding:'15px',
margin:'20px 0',
}}
>
Visualiser mon CV
</a>
<br />
</Typography>
</Fragment>
);
}
return "";
}
openDialog() {
this.setState({ open: true });
}
closeDialog() {
this.setState({ open: false });
}
refreshDialog() {
this.setState({ open: false });
window.location.reload();
}
onChange = (e) => {
this.setState({
value: e.target.value
});
if (e.target.value === '') {
console.log('cleared');
//this.props.onSelectionChanged('');
}
}
remplirLocation = (typeDonnee, donnee) =>{
console.log("DEBUT remplirLocation");
console.log(typeDonnee);
console.log(donnee);
if(typeDonnee=='"street_number"') {
this.setState({ street_number: donnee.replace('"', '') })
}else if(typeDonnee=='"route"') {
this.setState({ route: donnee.replace('"', '') })
}else if(typeDonnee=='"locality"') {
this.setState({ locality: donnee.replace('"', '') })
}else if(typeDonnee=='"administrative_area_level_2"') {
this.setState({ administrative_area_level_2: donnee.replace('"', '') })
}else if(typeDonnee=='"administrative_area_level_1"') {
this.setState({ administrative_area_level_1: donnee.replace('"', '') })
}else if(typeDonnee=='"country"') {
this.setState({ country: donnee.replace('"', '') })
}else if(typeDonnee=='"postal_code"') {
this.setState({ postal_code: donnee.replace('"', '') })
}
console.log("FIN remplirLocation");
}
onSuggestionSelected = (suggestion) => {
console.log('Selected suggestion:', suggestion)
let address = suggestion.description;
var words = address.split(',');
if(words.length<3){
address = "mairie de "+address;
}
this.setState({ geoloc: address})
this.setState({
value: address
});
geocodeByAddress(address)
.then(address => {
console.log("ADRESSE");
console.log(address);
if(address[0].address_components[0]){
this.remplirLocation(JSON.stringify(address[0].address_components[0].types[0]), JSON.stringify(address[0].address_components[0].long_name))
}
if(address[0].address_components[1]){
this.remplirLocation(JSON.stringify(address[0].address_components[1].types[0]), JSON.stringify(address[0].address_components[1].long_name))
}
if(address[0].address_components[2]){
this.remplirLocation(JSON.stringify(address[0].address_components[2].types[0]), JSON.stringify(address[0].address_components[2].long_name))
}
if(address[0].address_components[3]){
this.remplirLocation(JSON.stringify(address[0].address_components[3].types[0]), JSON.stringify(address[0].address_components[3].long_name))
}
if(address[0].address_components[4]){
this.remplirLocation(JSON.stringify(address[0].address_components[4].types[0]), JSON.stringify(address[0].address_components[4].long_name))
}
if(address[0].address_components[5]){
this.remplirLocation(JSON.stringify(address[0].address_components[5].types[0]), JSON.stringify(address[0].address_components[5].long_name))
}
if(address[0].address_components[6]){
this.remplirLocation(JSON.stringify(address[0].address_components[6].types[0]), JSON.stringify(address[0].address_components[6].long_name))
}
if(address[0].geometry){
console.log(address[0].geometry.location_type);
let gps =JSON.stringify(address[0].geometry.location);
const obj = JSON.parse(gps);
this.setState({ formatted_address: JSON.stringify(address[0].formatted_address) })
this.setState({ lat: obj.lat.toString()})
this.setState({ lng: obj.lng.toString()})
}
// console.log("GEOLOC ON geocodeByAddress")
// console.log(this.state.geoloc)
// document.getElementById("geoloc").value =JSON.stringify(address[0]);
// this.props.onSelectionChanged(address[0]);
})
.catch(error => console.error('Error', error))
}
onSuggestionSelected(suggestion) {
// Add your business logic here. In this case we just log...
console.log('Selected suggestion:', suggestion)
}
renderFunc = ({ getInputProps, getSuggestionItemProps, suggestions, loading }) => (
<div>
<input className={styles.inputSearchBar} {...getInputProps()} />
<div >
{loading && <div>Loading...</div>}
{suggestions.map(suggestion => {
const className = suggestion.active ? 'suggestion-item--active' : 'suggestion-item';
const style = suggestion.active
? { backgroundColor: 'red', cursor: 'pointer',border: '1px solid' }
: { backgroundColor: '#123456', cursor: 'pointer',border: '1px solid' };
return (<div {...getSuggestionItemProps(suggestion,{className,style})}>
<span >{suggestion.description}</span>
</div>
)
})}
</div>
</div>
);
callbackFunc = ( autoCompleteData ) => {
//You can use the address data, passed by autocomplete as you want.
}
handleChange = (e) => {
this.setState({ [e.target.name]: e.target.value })
}
onSubmit = (e) => {
e.preventDefault()
//TODO : Vérifier si le nom et prénom sont renseignés
console.log("firstname")
console.log(this.state.firstname)
const data = new FormData()
data.append('firstname', this.state.firstname)
data.append('lastname', this.state.lastname)
data.append('phone', this.state.phone)
data.append('currentJob', this.state.currentJob)
console.log("GEOLOC ON SUBMIT")
console.log(this.state)
data.append('geoloc', this.state.geoloc)
data.append('street_number', this.state.street_number.replace('"', ''))
data.append('route', this.state.route.replace('"', ''))
data.append('locality', this.state.locality.replace('"', ''))
data.append('administrative_area_level_2', this.state.administrative_area_level_2.replace('"', ''))
data.append('administrative_area_level_1', this.state.administrative_area_level_1.replace('"', ''))
data.append('country', this.state.country.replace('"', ''))
data.append('postal_code', this.state.postal_code.replace('"', ''))
data.append('formatted_address', this.state.formatted_address.replace('"', ''))
data.append('lat', this.state.lat)
data.append('lng', this.state.lng)
//
data.append('linkedin', this.state.linkedin)
data.append('twitter', this.state.twitter)
data.append('website', this.state.website)
//TODO:maybe add this two in a single transactionnal saga
this.props.updateUserRequest(data)
//TODO: faire appel à une méthode qui va encoyer le mail a l'entreprise
// this.props.companyMails.map((user) =>
// //TODO Envoyer un mail a chaque user
// console.log(user.email)
// )
// US 471 : TODO envoyer le lien du cv pour le mettre dans la candidature (this.state.cvLink)
console.log(this.state.cvLink, "lien CV")
this.props.postAdAnswerRequest(
{
adId: this.props.adId,
companyId: this.props.companyId,
mediaId: this.props.mediaId,
mediaUrl: this.props.mediaUrl,
thumbnails : this.props.thumbnails,
heure: this.props.heure
})
}
// inputFilesystemChange = (e) => {
// console.log("inputFilesystemChange");
// var file = e.target.files[0]
// this.setState({ picture: file })
// const data = new FormData()
// data.append('file', file)
// this.props.updateUserPictureRequest(data)
// }
recupererAdresse =()=>{
geocodeByAddress('1 rue de la laine, Questembert')
.then(results => getLatLng(results[0]))
.then(({ lat, lng }) =>
console.log('Successfully got latitude and longitude', { lat, lng })
)
geocodeByAddress('1 rue de la laine, Questembert')
.then(results => console.log(results))
.catch(error => console.error(error));
}
render() {
const { classes, user } = this.props
const logoUrl = user.picture;
const { loading } = this.state;
const inputProps = {
value: this.state.address,
onChange: this.onChange,
}
const searchOptions = {
componentRestrictions: { country: ['fr'] },
}
return (
<section className={classes.container}>
<form className={classes.form}
autoComplete="off">
{!!logoUrl && <Avatar className={classes.logo}
classes={{ img: classes.MuiAvatarImg }}
src={publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.postedContentUrl + logoUrl} alt="candidatLogo" />}
{/* {!!user.pictureLoading && <Loader />} */}
{/* {!!!user.pictureLoading && !!!logoUrl &&
(<Fragment><input
type="file" accept="image/*" capture="filesystem"
className={classes.input}
style={{ display: 'none' }}
id="raised-button-file"
multiple
type="file"
onChange={this.inputFilesystemChange}
/>
<label htmlFor="raised-button-file">
<Button component="span" className={classes.importButton} classes={{ root: classes.rootButton }}>
<img alt="talents-tube" src='/static/images/default/account-avatar-default.svg'
className={classes.iconButton} />
<Typography align="left" className={classes.textButton}>
J'<span className={classes.underlined}>importe</span> ma photo de profil
</Typography>
<KeyboardArrowRightIcon className={classes.InputKeyboardArrowRightIcon} />
</Button>
</label></Fragment>)
} */}
<Player fluid={false} width={"75%"} height={350}
playsInline className={classes.player}
src={publicRuntimeConfig.symphonyUrl + "uploads/videos/"+this.state.mediaUrl}
//src={this.state.mediaUrl}
// src="https://media.w3.org/2010/05/sintel/trailer_hd.mp4"
/>
<Button className={classes.remplacerButton} onClick={this.openDialog.bind(this)}>
Remplacer ma vidéo
</Button>
<Dialog open={this.state.open}>
<DialogTitle> Souhaitez-vous remplacer votre vidéo de réponse ?</DialogTitle>
<DialogContent className={classes.popup}> Cette vidéo et tous les éléments de votre candidature seront définitivement supprimés. Vous pourrez importer ou réaliser une nouvelle vidéo de réponse. </DialogContent>
<DialogActions>
<Button onClick={this.closeDialog.bind(this)} autoFocus>
Annuler
</Button>
<Button onClick={this.refreshDialog.bind(this)} >
Remplacer
</Button>
</DialogActions>
</Dialog>
<TextField
name="firstname"
required
id="outlined-required"
label="Prénom"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
value={this.state.firstname}
onChange={this.handleChange}
error={!!_.isEmpty(this.state.firstname)}
helperText={!!_.isEmpty(this.state.firstname) && "Veuillez saisir votre prénom"}
/>
<TextField
name="lastname"
required
id="outlined-required"
label="Nom"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
value={this.state.lastname}
onChange={this.handleChange}
error={!!_.isEmpty(this.state.lastname)}
helperText={!!_.isEmpty(this.state.lastname) && "Veuillez saisir votre nom"}
required
/>
<div
className={classes.conteneurGoogle}
classes={{ root: classes.rootTextfield }}
style={{ position: 'relative', zIndex:2, width: '100%' }}>
<label htmlFor="outlined-required"
className={classes.labelGeoloc}>
Adresse
</label>
<div className={classes.conteneurGoogleComposant}>
<GooglePlaceAutocomplete
style={{ paddingLeft:'14px !important', left: 0, right: 0, zIndex: '2 !important', width: '100%' }}
name="location"
label="Location"
id="outlined-required"
variant="outlined"
textFieldProps={{ id: "outlined-required" }}
className={classes.textField}
classes={{ root: classes.rootTextfield }}
options={this.searchOptions}
onSuggestionSelected={this.onSuggestionSelected}
textFieldProps={{ onChange: (e) => this.onChange(e), value: this.state.value, placeholder: 'Ex : Rue de Rivoli, Paris, France', fullWidth: true, size:"small"}}
types={['(regions)']}
componentRestrictions={{country: 'fr'}}
renderTarget={() => (
<div
style={{
width: '100%',
zIndex:9
}}
>
</div>
)}
/>
</div>
{/* <Input
name="geoloc"
id="geoloc"
label="geoloc"
ref="geoloc"
onChange={this.handleChange}
value={this.state.geoloc =='null' || this.state.geoloc =='' ? '' :this.state.geoloc}
/> */}
</div>
<TextField
name="phone"
id="outlined"
label="Téléphone"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
value={this.state.phone}
onChange={this.handleChange}
type="tel"
helperText="Renseignez votre numéro de téléphone pour permettre au recruteur de vous contacter"
/>
<TextField
disabled
id="outlined-required"
label="E-mail"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
value={user.email}
/>
<TextField
name="currentJob"
id="outlined"
label="Poste actuel"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
value={this.state.currentJob =='null' || this.state.currentJob =='' ? '' :this.state.currentJob}
onChange={this.handleChange}
/>
{this.AfficherSuccess()}
<div className={classes.containerImport}>
<input
type="file"
accept=".doc,.docx,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document, .pdf, .odt"
className={classes.input+' cypButtonImportVid'}
style={{ display: 'none' }}
id="import-button-file"
onChange={this.inputFilesystemChange}
/>
<label htmlFor="import-button-file">
<Button component="span" className={classes.importButton} classes={{ root: classes.rootButton }}>
<GetApp className={classes.icon} /> Importer mon CV
</Button>
</label>
<Hidden>&nbsp;</Hidden>
{this.AfficherLienCv()}
</div>
<TextField
name="linkedin"
id="outlined"
label="Linkedin"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
placeholder="http://www.linkedin.com/in/"
value={this.state.linkedin =='null' || this.state.linkedin =='' ? '' :this.state.linkedin}
onChange={this.handleChange}
/>
<TextField
name="twitter"
id="outlined"
label="Twitter"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
placeholder="http://twitter.com/.."
value={this.state.twitter =='null' || this.state.twitter =='' ? '' :this.state.twitter}
onChange={this.handleChange}
/>
<TextField
name="website"
id="outlined"
label="Site internet"
className={classes.textField}
classes={{ root: classes.rootTextfield }}
variant="outlined"
placeholder="http://monsite.fr"
value={this.state.website =='null' || this.state.website =='' ? '' :this.state.website}
onChange={this.handleChange}
/>
</form>
<div id="F" className={classes.foot}>
<Button variant="contained" className={classes.button + ' cypButtonSendApplication'} onClick={this.onSubmit}>Envoyer ma candidature</Button>
</div>
</section>
)
}
}
function mapStateToProps(state, ownProps) {
// console.log(state.media.message.heure);
return {
user: state.user ,
cvLink : state.mediaCv.message,
loading: !!state.media.loading,
cv : true,
// user: state.user,
// loading: !!state.user.loading,
pictureLoading: !!state.user.pictureLoading,
errors: state.user.errors || ownProps.errors,
mediaId: state.media.message && state.media.message.mediaId,
mediaUrl: state.media.message && state.media.message.originalUrl,
thumbnails: state.media.message && state.media.message.thumbnails,
mediaUrlVimeo: state.media.message && state.media.message.uriVimeo,
mediaFileName: state.media.message && state.media.message.filename,
heure: state.media.message && state.media.message.heure,
};
}
export default withStyles(styles)(connect(mapStateToProps, { postAdAnswerRequest, updateUserRequest, updateUserPictureRequest, uploadMediaCv })(Answer))
-263
View File
@@ -1,263 +0,0 @@
import React, { Fragment } from 'react';
import PropTypes from "prop-types";
import Router from 'next/router'
import getConfig from 'next/config'
import { withStyles } from '@material-ui/core/styles';
import Card from '@material-ui/core/Card';
import Chip from '@material-ui/core/Chip';
import CardContent from '@material-ui/core/CardContent';
import CardMedia from '@material-ui/core/CardMedia';
import Typography from '@material-ui/core/Typography';
import IconText from './../atoms/IconTextInline';
import KeyboardArrowleftIcon from '@material-ui/icons/PlayArrowRounded';
import ArrowForwardIcon from '@material-ui/icons/ArrowForward';
import Link from 'next/link';
const styles = theme => ({
card: {
display: 'flex',
minHeight: '21vh',
maxHeight: '25vh',
width: '100%',
margin: theme.spacing(1,0),
borderRadius: '5px',
cursor: 'pointer',
'& > div': {
padding: '0 !important',
},
[theme.breakpoints.up('md')]: {
width: '30%',
},
[theme.breakpoints.down('md')]: {
width: '40%',
},
[theme.breakpoints.down('xs')]: {
width: '100%',
},
[theme.breakpoints.up('sm')]: {
margin: '1vh 0 1vh 0',
},
},
detailsContainer: {
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-start',
padding: theme.spacing(3, 2),
width: '75%',
},
jobTitle: {
fontSize: '1em',
fontWeight: 'bold',
color: theme.palette.offerlistitem.title,
},
companyTitle: {
fontSize: '0.8em',
fontWeight: '300',
color: theme.palette.offerlistitem.title,
},
content: {
display: 'flex',
alignItems: 'center',
width: '100%',
padding: 0,
},
cover: {
position: 'relative',
width: '125px',
height: '100%',
backgroundPosition: 'center',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
},
iconPlay: {
fontSize: '2em',
color: theme.palette.background.grey,
position: 'absolute',
top: 'calc(50% - 0.5em)',
left: 'calc(50% - 0.5em)',
},
iconText: {
marginLeft: 0,
justifyContent: 'flex-start',
},
iconTextIcon: {
color: theme.palette.offerlistitem.icon,
fontSize: '1em',
},
iconTextText: {
color: theme.palette.offerlistitem.text,
fontSize: '1em',
paddingLeft: theme.spacing(1),
},
bottomCard: {
display: 'flex',
justifyContent: 'space-between',
width: '90%',
},
chip: {
marginTop :"10px",
backgroundColor:"#E7F3FF",
color:theme.palette.primary.dark,
},
icon: {
color: theme.palette.secondary.dark,
},
});
const { publicRuntimeConfig } = getConfig()
//TODO:shouldn't be here
//must go in API
const status = new Map([
["A_TRAITER"
, "Envoyée"]
,
["CONTACTE"
, "En cours de traitement"]
,
["ENTRETIEN"
, "En cours de traitement"]
,
["REFUSE"
, "Refusée"]
,
["EMBAUCHE"
, "Embauchée"]
,
["EXPIRED"
, "Expirée"]
,
[""
, "Envoyée"]
,
["Null"
, "Envoyée"]
,
])
class AnswerRowComponent extends React.Component {
render() {
const { classes, rowData, company } = this.props;
// company not used ?
let companyR = company
if (!!!company)
companyR = rowData.ad.company;
else
companyR = company;
console.log(rowData);
const ville = (rowData.ad && rowData.ad.location && rowData.ad.location.gmap_address && rowData.ad.location.gmap_address.address_components[0] )
? rowData.ad.location.gmap_address.address_components[0].long_name
: "ND"
const imgUrl = (rowData.ad && rowData.ad.video && rowData.ad.video.thumbnails[0] && rowData.ad.video.thumbnails[0].sizes[4])
? rowData.ad.video.thumbnails[0].sizes[4].link
: publicRuntimeConfig.adListDefaultUrl
const logoUrl = publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.cachedMediaUrl + companyR.logo
return (
<Link href={`/Candidature/${rowData.id}`} >
<Card className={classes.card} >
{rowData.ad ? (
<CardContent className={classes.content}>
<CardMedia
className={classes.cover}
image={imgUrl}
title={rowData.ad.title}
>
<KeyboardArrowleftIcon className={classes.iconPlay} />
</CardMedia>
<div className={classes.detailsContainer}>
<Typography
gutterBottom
variant="headline"
variant="h6"
component="h3"
className={classes.jobTitle}>
{rowData.ad.title&&rowData.ad.title}
</Typography>
<Typography
variant="headline"
variant="h6"
component="h4"
className={classes.companyTitle}>
{rowData.ad.company.brand_name&&rowData.ad.company.brand_name}
</Typography>
<Typography
variant="headline"
variant="h6"
component="h4"
className={classes.companyTitle}>
<IconText classes={{ root: classes.iconText, icon: classes.iconTextIcon, text: classes.iconTextText }} variant="place" text={ville} />
<IconText classes={{ root: classes.iconText, icon: classes.iconTextIcon, text: classes.iconTextText }} variant="assignment" text={rowData.ad.extra&&rowData.ad.extra.contract_type?rowData.ad.extra.contract_type:"ND"} />
<IconText classes={{ root: classes.iconText, icon: classes.iconTextIcon, text: classes.iconTextText }} variant="watch_later" text={(new Date(rowData.c_time)).toLocaleDateString("fr-FR")} />
</Typography>
<div className={ classes.bottomCard }>
<Chip size="small" label={status.get(rowData.status_reponse)? status.get(rowData.status_reponse) : "Envoyée" } className={classes.chip} />
<ArrowForwardIcon className={classes.icon} />
</div>
</div>
</CardContent>
):(
<CardContent className={classes.content}>
<CardMedia
className={classes.cover}
image={publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.cachedMediaUrl + rowData.company.logo}
title={rowData.company.brand_name}
>
<KeyboardArrowleftIcon className={classes.iconPlay} />
</CardMedia>
<div className={classes.detailsContainer}>
<Typography
gutterBottom
variant="headline"
variant="h6"
component="h3"
className={classes.jobTitle}>
Candidature spontanée
</Typography>
<Typography
variant="headline"
variant="h6"
component="h4"
className={classes.companyTitle}>
{rowData.company.brand_name&&rowData.company.brand_name}
</Typography>
<Typography
variant="headline"
variant="h6"
component="h4"
className={classes.companyTitle}>
<IconText classes={{ root: classes.iconText, icon: classes.iconTextIcon, text: classes.iconTextText }} variant="watch_later" text={(new Date(rowData.c_time)).toLocaleDateString("fr-FR")} />
</Typography>
<div className={ classes.bottomCard }>
<Chip size="small" label={status.get(rowData.status_reponse)? status.get(rowData.status_reponse) : "Envoyée" } className={classes.chip} />
<ArrowForwardIcon className={classes.icon} />
</div>
</div>
</CardContent>
)}
</Card>
</Link>
);
}
}
AnswerRowComponent.defaultProps = {
company: {}
}
AnswerRowComponent.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
rowData: PropTypes.object.isRequired,
company: PropTypes.object
};
export default withStyles(styles, { withTheme: true })(AnswerRowComponent);
@@ -1,39 +0,0 @@
import React, { Fragment } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import _ from "lodash"
import Ar from "lodash/array"
import VideoVimeo from '../atoms/VideoVimeo'
const useStyles = makeStyles(theme => ({
card: {
width: '100%',
},
title: {
fontSize: '1em',
fontWeight: '500',
},
titleBorder: {
'&:after': {
content: '""',
width: '15px',
borderBottom: 'solid 2px',
borderColor: theme.palette.primary.main + '!important',
display: 'flex',
},
},
video: {
[theme.breakpoints.up('md')]: {
paddingBottom: '35%', /* 16:9 */
},
}
}));
export default function CandidatureDetail(props) {
const classes = useStyles();
return (
<Fragment>
<VideoVimeo classes={{ video: classes.video }} videoId={Ar.last(_.split(props.video.cdn_url, '/'))} />
</Fragment>
);
}
-150
View File
@@ -1,150 +0,0 @@
import React, { Fragment, useState, useCallback } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import withWidth, { isWidthUp } from '@material-ui/core/withWidth'
import _ from "lodash"
import ChatCard from '../atoms/ChatCard'
import TextField from '@material-ui/core/TextField';
import { Button } from '@material-ui/core';
import IconAdd from '@material-ui/icons/Add';
import ArrowUpwardIcon from '@material-ui/icons/ArrowUpward';
import { useDispatch } from 'react-redux';
import { useSelector } from 'react-redux'
const useStyles = makeStyles(theme => ({
card: {
width: '100%',
},
wrapper: {
minHeight: '100%',
},
contain: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
[theme.breakpoints.up('md')]: {
padding: '2vh 18vw',
},
},
push: {
height: '50px'
},
foot: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
[theme.breakpoints.up('md')]: {
padding: '2vh 18vw',
},
},
chat: {
},
filterForm: {
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
backgroundColor: theme.palette.input.main,
padding: theme.spacing(1),
width: '100%',
[theme.breakpoints.up('md')]: {
padding: theme.spacing(3),
},
},
button: {
backgroundColor: 'inherit',
borderRadius: '0',
'& svg': {
fontSize: '1.5rem',
[theme.breakpoints.up('sm')]: {
fontSize: '2rem',
},
}
},
icon: {
color: theme.palette.secondary.main,
background: theme.palette.primary.important,
padding: theme.spacing(1),
borderRadius: '50%',
},
video: {
display: 'flex',
flexDirection: 'column',
height: '11vh',
},
title: {
fontSize: '1em',
fontWeight: '500',
},
titleBorder: {
'&:after': {
content: '""',
width: '15px',
borderBottom: 'solid 2px',
borderColor: theme.palette.primary.main + '!important',
display: 'flex',
},
},
}));
function Chat(props) {
const classes = useStyles();
const [text, setText] = useState("");
const dispatch = useDispatch()
const messages = useSelector(state => state.answer.messages);
const loadingMessage = useSelector(state => state.answer.loadingMessage);
const sendMessage = useCallback(
(message) => dispatch({ type: 'POST_MESSAGE_ANSWER_REQUEST', payload: { answerId: props.answerId, message: message } }),
[dispatch]
)
const postMessage = () => {
sendMessage(text);
setText('');
}
return (
<Fragment>
<div className={classes.wrapper}>
<div className={classes.contain}>
{
_.orderBy(messages, ['c_time'], ['asc']).map((message, index) => {
return <ChatCard message={message} key={index}></ChatCard>
})
}
</div>
</div>
<div id="F" className={classes.foot}>
<div className={classes.filterForm}>
<TextField
fullWidth
multiline
rows={isWidthUp('md', props.width) ? 8 : 1}
id="standard-search"
name="chattext"
value={text}
onChange={(e) => setText(e.target.value)}
placeholder={"Message"}
className={classes.textField}
InputLabelProps={{
shrink: true,
}}
/>
<Button onClick={()=>postMessage()}
disabled={loadingMessage}
variant="contained"
className={classes.button}>
<ArrowUpwardIcon className={classes.icon}/>
</Button >
</div>
</div>
</Fragment>
);
}
export default withWidth()(Chat)
+82 -107
View File
@@ -6,12 +6,10 @@ import { withStyles } from '@material-ui/core/styles';
import Avatar from '@material-ui/core/Avatar';
import Card from '@material-ui/core/Card';
import CardContent from '@material-ui/core/CardContent';
import CardHeader from '@material-ui/core/CardHeader';
import CardMedia from '@material-ui/core/CardMedia';
import Typography from '@material-ui/core/Typography';
import Chip from '@material-ui/core/Chip';
import IconText from './../atoms/IconText';
import KeyboardArrowleftIcon from '@material-ui/icons/PlayArrowRounded';
import Link from 'next/link';
const { publicRuntimeConfig } = getConfig()
@@ -19,57 +17,40 @@ const styles = theme => ({
card: {
display: 'flex',
position: 'relative',
height: '67vh',
height: '50vh',
width: '100%',
cursor: 'pointer',
transform: 'translateY(-0px)',
transition: 'transform 0.25s',
'&:hover': {
transform: 'translateY(-15px)',
transition: 'transform 0.5s, box-shadow 1.2s',
'& .cardHover': {
backgroundColor: 'rgba(0,0,0,0)',
},
},
[theme.breakpoints.up('md')]: {
width: '30%',
height: '53vh',
width : '30%',
},
[theme.breakpoints.down('md')]: {
width: '40%',
height: '67vh',
width : '40%',
},
[theme.breakpoints.down('xs')]: {
width: '100%',
width : '100%',
},
margin: theme.spacing(1.5),
marginBottom: theme.spacing(3),
margin: '1vh 2vh 1vh 2vh',
[theme.breakpoints.up('sm')]: {
margin: theme.spacing(2, 0),
margin: '1vh 0 1vh 0',
},
borderRadius: '4px',
borderRadius: 0
},
detailsContainer: {
details_container: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
width: '100%',
paddingTop: theme.spacing(6),
padding: '8vh 0 0 0',
},
companyTitle: {
textAlign: 'center',
company_title: {
fontSize: '1em',
fontWeight: '500',
minHeight: '5vh',
padding: theme.spacing(0,1.5),
fontWeight: 'normal',
textTransform: 'uppercase',
},
content: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'space-between',
flexWrap: 'wrap',
width: '100%',
padding: 0,
@@ -79,108 +60,102 @@ const styles = theme => ({
height: '50%',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
position: 'relative',
backgroundBlendMode: 'darken',
backgroundColor: 'rgba(30,35,39,0.25)',
transition: 'background-color 1s',
},
logoContainer: {
logo_container: {
display: 'flex',
alignItems: 'center',
width: 85,
height: 85,
width: 100,
height: 100,
position: 'absolute',
left: '50%',
top: '50%',
transform: 'translate(-50%, -66%)',
border: 'solid 5px white',
backgroundColor: 'white',
boxShadow: '0px 6px 15px rgba(30, 35, 39, 0.10)',
borderRadius: '6px',
},
iconTextContainer: {
width: '100%',
},
iconText: {
marginLeft: 0,
padding: theme.spacing(2, 3),
justifyContent: 'flex-start',
},
iconTextIcon: {
color: theme.palette.offerlistitem.icon,
fontSize: '1em',
},
iconTextText: {
color: theme.palette.offerlistitem.text,
fontSize: '0.8em',
textTransform: 'capitalize',
paddingLeft: theme.spacing(1),
},
iconPlay: {
fontSize: '3em',
color: theme.palette.background.grey,
position: 'absolute',
top: 'calc(50% - 0.5em)',
left: 'calc(50% - 0.5em)',
boxShadow: '0 8px 6px -6px grey',
},
logo: {
width: '100%',
height: 'auto',
objectFit: 'contain',
borderRadius: '0px',
objectfit: 'contain',
borderRadius: 0,
},
chip: {
margin: '0 1vh 0 1vh',
}
});
class CompanyRowComponent extends React.Component {
render() {
const { classes, theme, rowData } = this.props;
const imgDefaultUrl = "https://blog.talentstube.com/wp-content/uploads/2021/01/default_picture_company.jpg"
const imgDefaultUrl = "https://www.talentstube.com/img/default_picture_company.svg"
const imgUrl = (rowData.presentation_video && rowData.presentation_video.thumbnails[0] && rowData.presentation_video.thumbnails[0].sizes[4]) ? rowData.presentation_video.thumbnails[0].sizes[4].link : imgDefaultUrl
const logoUrl = publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.cachedMediaUrl + rowData.logo
let location = "non renseigné"
if (rowData.addresses && rowData.addresses.billing && rowData.addresses.billing.city && rowData.addresses.billing.postcode)
location = (rowData.addresses.billing.city.toLowerCase() + ', ' + rowData.addresses.billing.postcode);
const logoUrl = publicRuntimeConfig.logoRootUrl + rowData.logo
const offre = (rowData.count_ads == 1) ? rowData.count_ads + ' offre' : rowData.count_ads + ' offres';
const nbOffre = (rowData.count_ads > 0) ? offre : 'Candidature spontanée';
return (
<Link href={`/Entreprise/${rowData.id}-${_.kebabCase(rowData.brand_name)}`} >
<Card className={classes.card + ' cypCardCompany'}>
<CardContent className={classes.content}>
<CardMedia
className={classes.cover + ' cardHover'}
image={imgUrl}
title={rowData.brand_name}
>
<KeyboardArrowleftIcon className={classes.iconPlay} />
</CardMedia>
<div className={classes.logoContainer}>
<Avatar className={classes.logo} src={logoUrl} alt="companylogo" />
</div>
<Card onClick={() => Router.push(`/Company?id=${rowData.id}`)}>
<CardContent className={classes.content}>
<CardMedia
className={classes.cover}
image={imgUrl}
title={rowData.title}
/>
<div className={classes.detailsContainer}>
<Typography
variant="headline"
variant="h6"
component="h3"
className={classes.companyTitle}>
{rowData.brand_name}
</Typography>
<div className={classes.iconTextContainer}>
<IconText classes={{ root: classes.iconText, icon: classes.iconTextIcon, text: classes.iconTextText }} variant="location_on" text={location} />
</div>
</div>
<Chip color="primary" label={nbOffre} className={classes.chip} />
</CardContent>
</Card>
</Link>
<div className={classes.logo_container}>
<Avatar className={classes.logo} src={logoUrl} />
</div>
<div className={classes.details_container}>
<Typography
gutterBottom
variant="headline"
variant="h6"
component="h4"
align="center"
className={classes.company_title}>
{rowData.business_name}
</Typography>
{/* <Typography
gutterBottom
variant="headline"
variant="h6"
component="h3"
align="center"
className={classes.job_title}>
{rowData.title}
</Typography> */}
</div>
<div>
{/* <Chip label={rowData.extra.contract_type} className={classes.chip} />
<Chip label={rowData.location.gmap_address.address_components[0].long_name} className={classes.chip} /> */}
</div>
</CardContent>
{/* <CardHeader />
<CardContent>
<CardMedia
className={classes.cover}
image={imgUrl}
title={rowData.presentation_video&&rowData.presentation_video.title}
/>
<Typography gutterBottom component="h3"
className={classes.details}>
{rowData.brand_name}
</Typography>
<Typography gutterBottom component="h4"
className={classes.details}>
{rowData.website}
</Typography>
<Typography gutterBottom component="h5"
className={classes.details}>
{rowData.description}
</Typography>
</CardContent> */}
</Card>
);
}
}
+7 -284
View File
@@ -1,299 +1,22 @@
import Link from 'next/link'
import { withStyles } from '@material-ui/core/styles'
import { Typography } from '@material-ui/core';
import { Fragment } from 'react';
import NewsLetterRegistration from './NewsLetterRegistration'
import dynamic from 'next/dynamic'
import Button from '@material-ui/core/Button'
import getConfig from 'next/config'
const PWAInstallSnack = dynamic(() => import('./PWAInstallSnack'), {
ssr: false
});
const { publicRuntimeConfig } = getConfig();
import { Fragment, Children } from 'react';
import { Button } from '@material-ui/core';
const styles = theme => ({
root: {
display: 'flex',
flexDirection: 'column',
backgroundColor: theme.palette.primary.main,
[theme.breakpoints.up('md')]: {
display: 'flex',
flexDirection: 'row',
alignItems: 'flex-start',
justifyContent: 'space-around',
backgroundColor: theme.palette.primary.main,
padding: theme.spacing(10, 18),
},
'& a': {
textDecoration: 'none',
},
position: 'relative',
height: '10vh'
},
container: {
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-start',
padding: theme.spacing(0, 5),
paddingBottom: theme.spacing(3.5),
'&:first-child': {
paddingTop: theme.spacing(4),
},
[theme.breakpoints.up('md')]: {
padding: 0,
'&:first-child': {
paddingTop: 0,
},
},
},
containerRegion: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
backgroundColor: theme.palette.secondary.main,
padding: theme.spacing(3),
[theme.breakpoints.up('md')]: {
padding: theme.spacing(8, 0),
},
},
titleContainer: {
color: theme.palette.primary.darkMain,
fontSize: '1.5em',
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
fontWeight: '600',
[theme.breakpoints.up('md')]: {
fontSize: '1.2em',
paddingBottom: theme.spacing(2),
},
},
textContainer: {
fontWeight: '300',
fontSize: '0.9em',
[theme.breakpoints.up('md')]: {
fontWeight: '300',
fontSize: '0.8em',
},
},
textContainerRegion: {
fontWeight: '300',
fontSize: '0.9em',
color: theme.palette.primary.dark,
},
footerLogo: {
width: '15vw',
[theme.breakpoints.up('md')]: {
width: '4vw',
},
},
footerLogoTT: {
width: '70%',
[theme.breakpoints.up('md')]: {
paddingBottom: theme.spacing(1),
width: '100%'
},
},
containerReactApp: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'space-between',
height: 'auto',
paddingTop: theme.spacing(4),
backgroundColor: theme.palette.primary.main,
[theme.breakpoints.down('xs')]: {
height: '100vh',
},
[theme.breakpoints.up('md')]: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-around',
height: '35vh',
padding: theme.spacing(6, 1),
position: 'relative',
},
},
titleReactApp: {
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
fontSize: '1.5em',
fontWeight: '600',
paddingTop: theme.spacing(4),
paddingLeft: theme.spacing(4),
paddingRight: theme.spacing(4),
[theme.breakpoints.up('md')]: {
order: 1,
width: '20%',
textAlign: 'left',
},
},
buttonReactApp: {
textTransform: 'inherit',
margin: theme.spacing(0, 8),
padding: theme.spacing(1.2, 2),
[theme.breakpoints.up('md')]: {
order: 3,
margin: 'inherit',
marginRight: '5vw',
},
},
imageReactApp: {
width: '100%',
[theme.breakpoints.up('sm')]: {
width: 'auto',
},
[theme.breakpoints.up('md')]: {
width: '25%',
order: 2,
position: 'absolute',
bottom: 0,
},
},
containerNewsletter: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
padding: theme.spacing(6, 4),
},
version:{
marginTop: '15px',
fontSize: '0.7em',
fontWeight: '300',
}
});
function Footer(props) {
const { classes } = props;
return (
<div>
<PWAInstallSnack >
{({ initInstall }) =>
<section
className={classes.containerReactApp}
>
<Typography
gutterBottom
color="secondary"
align="center"
component="h3"
className={classes.titleReactApp}
>
Installez l'application Talents Tube pour suivre vos candidatures
</Typography>
<Button
aria-label='install'
variant="outlined"
color="secondary"
onClick={initInstall}
className={classes.buttonReactApp}
>
Installer l'application
</Button>
<img alt="télécharger-pwa" src='/static/images/newsletter/application.png' className={classes.imageReactApp} />
</section>
}
</PWAInstallSnack>
<Fragment>
{props.children}
</Fragment>
<section className={classes.containerNewsletter}>
<NewsLetterRegistration />
</section>
<div className={classes.root}>
<section className={classes.container}>
<img alt="talents-tube" src='/static/images/logos/TalentsTube_logo-blanc.svg' className={classes.footerLogoTT} />
<Link href="/Offres" >
<a>
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
Offre d'emploi
</Typography>
</a>
</Link>
<Link href="/Entreprises" >
<a>
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
Entreprises
</Typography>
</a>
</Link>
<Link href="/Help" >
<a>
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
Comment ça marche ?
</Typography>
</a>
</Link>
<a href="https://blog.talentstube.com" target="_blank">
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}
>
Blog
</Typography>
</a>
</section>
<section className={classes.container}>
<Typography color="secondary" component="p" className={classes.titleContainer}>
Informations
</Typography>
<Link href="/Cgu" >
<a>
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
CGU
</Typography>
</a>
</Link>
<Link href="/MentionsLegales" >
<a>
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
Mentions légales
</Typography>
</a>
</Link>
<Link href="/Confidentialite" >
<a>
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
Politique de confidentialité et Protection <br />des données
</Typography>
</a>
</Link>
<Link href="" >
<a href="https://blog.talentstube.com/contact" target="_blank">
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
Contact
</Typography>
</a>
</Link>
</section>
<section className={classes.container}>
<Typography color="secondary" component="p" className={classes.titleContainer}>
Rencontrons-nous
</Typography>
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
3, rue Louis de Broglie
</Typography>
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
56 000 Vannes
</Typography>
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
<a href="tel:+33230050631" >02.30.05.06.31 </a>
</Typography>
{/* <Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
contact@talentstube.com
</Typography> */}
</section>
</div>
<section className={classes.containerRegion}>
<Typography gutterBottom component="p" className={classes.textContainerRegion} align="center" >
Entreprise soutenue par
</Typography>
<a href="https://www.bretagne.bzh/" target="_blank" className={classes.darkMenuItem} rel="noopener">
<img alt="Région Bretagne" src='/static/images/logos/Logo-region.svg' className={classes.footerLogo} />
</a>
<Typography className={classes.version} align="center" >
{publicRuntimeConfig.version}
</Typography>
</section>
</div>
);
}
@@ -1,246 +0,0 @@
import Link from 'next/link'
import { withStyles } from '@material-ui/core/styles'
import { Typography } from '@material-ui/core';
import { Fragment } from 'react';
import NewsLetterRegistration from './NewsLetterRegistration'
import dynamic from 'next/dynamic'
import Button from '@material-ui/core/Button'
import getConfig from 'next/config'
const { publicRuntimeConfig } = getConfig();
const styles = theme => ({
root: {
display: 'flex',
flexDirection: 'column',
backgroundColor: "#1E2327",
[theme.breakpoints.up('md')]: {
display: 'flex',
flexDirection: 'row',
alignItems: 'flex-start',
justifyContent: 'space-around',
backgroundColor: "#1E2327",
padding: theme.spacing(10, 18),
},
'& a': {
textDecoration: 'none',
color:"#fff"
},
},
container: {
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-start',
padding: theme.spacing(0, 5),
paddingBottom: theme.spacing(3.5),
'&:first-child': {
paddingTop: theme.spacing(4),
},
[theme.breakpoints.up('md')]: {
padding: 0,
'&:first-child': {
paddingTop: 0,
},
},
},
containerRegion: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
backgroundColor: theme.palette.secondary.main,
padding: theme.spacing(3),
[theme.breakpoints.up('md')]: {
padding: theme.spacing(8, 0),
},
},
titleContainer: {
color: "#fff",
fontSize: '1.5em',
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
fontWeight: '600',
[theme.breakpoints.up('md')]: {
fontSize: '1.2em',
paddingBottom: theme.spacing(2),
},
},
textContainer: {
fontWeight: '300',
fontSize: '0.9em',
[theme.breakpoints.up('md')]: {
fontWeight: '300',
fontSize: '0.8em',
},
},
textContainerRegion: {
fontWeight: '300',
fontSize: '0.9em',
color: theme.palette.primary.dark,
},
footerLogo: {
width: '15vw',
[theme.breakpoints.up('md')]: {
width: '4vw',
},
},
footerLogoTT: {
width: '70%',
[theme.breakpoints.up('md')]: {
paddingBottom: theme.spacing(1),
width: '100%'
},
},
containerReactApp: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'space-between',
height: 'auto',
paddingTop: theme.spacing(4),
backgroundColor: "#000",
[theme.breakpoints.down('xs')]: {
height: '100vh',
},
[theme.breakpoints.up('md')]: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-around',
height: '35vh',
padding: theme.spacing(6, 1),
position: 'relative',
},
},
titleReactApp: {
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
fontSize: '1.5em',
fontWeight: '600',
paddingTop: theme.spacing(4),
paddingLeft: theme.spacing(4),
paddingRight: theme.spacing(4),
[theme.breakpoints.up('md')]: {
order: 1,
width: '20%',
textAlign: 'left',
},
},
buttonReactApp: {
textTransform: 'inherit',
margin: theme.spacing(0, 8),
padding: theme.spacing(1.2, 2),
[theme.breakpoints.up('md')]: {
order: 3,
margin: 'inherit',
marginRight: '5vw',
},
},
imageReactApp: {
width: '100%',
[theme.breakpoints.up('sm')]: {
width: 'auto',
},
[theme.breakpoints.up('md')]: {
width: '25%',
order: 2,
position: 'absolute',
bottom: 0,
},
},
containerNewsletter: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
padding: theme.spacing(6, 4),
},
version:{
marginTop: '15px',
fontSize: '0.7em',
fontWeight: '300',
}
});
function Footer(props) {
const { classes } = props;
return (
<div>
<section className={classes.containerNewsletter}>
<NewsLetterRegistration />
</section>
<div className={classes.root}>
<section className={classes.container}>
<img alt="talents-tube" src='/static/images/logos/TalentsTube_logo-blanc.svg' className={classes.footerLogoTT} />
</section>
<section className={classes.container}>
<Typography color="secondary" component="p" className={classes.titleContainer}>
Informations
</Typography>
<Link href="/Cgu" >
<a>
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
CGU
</Typography>
</a>
</Link>
<Link href="/MentionsLegales" >
<a>
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
Mentions légales
</Typography>
</a>
</Link>
<Link href="/Confidentialite" >
<a>
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
Politique de confidentialité et Protection <br />des données
</Typography>
</a>
</Link>
<Link href="" >
<a href="https://blog.talentstube.com/contact" target="_blank">
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
Contact
</Typography>
</a>
</Link>
</section>
<section className={classes.container}>
<Typography color="secondary" component="p" className={classes.titleContainer}>
Rencontrons-nous
</Typography>
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
3, rue Louis de Broglie
</Typography>
<Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
56 000 Vannes
</Typography>
<Typography gutterBottom component="p" className={classes.textContainer}>
<a href="tel:+33230050631" >02.30.05.06.31 </a>
</Typography>
{/* <Typography gutterBottom color="secondary" component="p" className={classes.textContainer}>
contact@talentstube.com
</Typography> */}
</section>
</div>
<section className={classes.containerRegion}>
<Typography gutterBottom component="p" className={classes.textContainerRegion} align="center" >
Entreprise soutenue par
</Typography>
<a href="https://www.bretagne.bzh/" target="_blank" className={classes.darkMenuItem} rel="noopener">
<img alt="Région Bretagne" src='/static/images/logos/Logo-region.svg' className={classes.footerLogo} />
</a>
<Typography className={classes.version} align="center" >
{publicRuntimeConfig.version}
</Typography>
</section>
</div>
);
}
export default withStyles(styles)(Footer)
@@ -1,9 +0,0 @@
import React from 'react';
const NextButton = ({ hasNext, onClick, style, className, text }) => hasNext ? (
// <button type="button" onClick={onClick} style={style} className={className}>Suivant</button>
<div></div>
) :
null;
export default NextButton;
@@ -1,35 +0,0 @@
// import React, { useState } from 'react';
// import Pagination from '@material-ui/lab/Pagination';
// import PaginationItem from '@material-ui/lab/PaginationItem';
// export default function GriddleCustomPageDropdown(props) {
// let [page] = React.useState(1);
// let PageDropDown = null;
// const setPage = (event, newPage) => {
// console.log('test');
// setPage(newPage);
// };
// return (
// <Pagination count={props.maxPages} defaultPage={props.currentPage} onChange={props.setPage}/>
// );
// }
// const [page, setPage] = useState(1);
// const handleChangePage = (event, newPage) => {
// setPage(newPage);
// };
// const PageDropDown = ({ maxPages, currentPage, setPage }) => <Pagination count={maxPages} defaultPage={currentPage} onChangePage={handleChangePage}/> ;
// export default PageDropDown;
import React from 'react';
import Pagination from '@material-ui/lab/Pagination';
const NextButton = ({ maxPages, currentPage, setPage, className, text }) => maxPages ? (
<Pagination count={maxPages} defaultPage={currentPage} onChange={setPage} shape="rounded"/>
) :
null;
export default NextButton;
@@ -1,9 +0,0 @@
import React from 'react';
const PreviousButton = ({ hasPrevious, onClick, style, className, text }) => hasPrevious ? (
// <button type="button" onClick={onClick} style={style} className={className}>Précédent</button>
<div></div>
) :
null;
export default PreviousButton;
+196 -599
View File
@@ -1,62 +1,43 @@
import React, { Fragment, Children } from 'react';
import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import IconButton from '@material-ui/core/IconButton';
import Typography from '@material-ui/core/Typography';
import { withStyles, getMuiTheme } from '@material-ui/core/styles';
import MenuIcon from '@material-ui/icons/Menu';
import Link from 'next/link'
import Drawer from '@material-ui/core/Drawer';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import Divider from '@material-ui/core/Divider';
import HomeIcon from '@material-ui/icons/HomeOutlined';
import OfferIcon from '@material-ui/icons/LocalOfferOutlined';
import CompanyIcon from '@material-ui/icons/DomainOutlined';
import HelpIcon from '@material-ui/icons/HelpOutline';
import VideoIcon from '@material-ui/icons/OndemandVideoOutlined';
import NotesIcon from '@material-ui/icons/NotesOutlined';
import SupervisorAccountIcon from '@material-ui/icons/SupervisorAccount';
import PersonIcon from '@material-ui/icons/Person';
import PersonAddIcon from '@material-ui/icons/PersonAdd';
import WorkOutlineIcon from '@material-ui/icons/WorkOutline';
import AccountCircleOutlinedIcon from '@material-ui/icons/AccountCircleOutlined';
import FolderSharedIcon from '@material-ui/icons/FolderShared';
import AccountCircleIcon from '@material-ui/icons/AccountCircle';
import PermContactCalendar from '@material-ui/icons/PermContactCalendar';
import VideoCam from '@material-ui/icons/Videocam';
import SettingsIcon from '@material-ui/icons/Settings';
import PowerSettingsNewIcon from '@material-ui/icons/PowerSettingsNew';
import ArrowForward from '@material-ui/icons/ArrowForward';
import SendIcon from '@material-ui/icons/Send';
import CodeIcon from '@material-ui/icons/Code';
import HomeIcon from '@material-ui/icons/Home';
import FingerprintIcon from '@material-ui/icons/Fingerprint';
import LocalBarIcon from '@material-ui/icons/LocalBar';
import AccountCircle from '@material-ui/icons/AccountCircle';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import { ListItemText } from '@material-ui/core';
import Loader from './../templates/loader'
import CircularProgress from '@material-ui/core/CircularProgress';
import { connect } from 'react-redux'
import { fetchCurrentUserRequest } from "../../actions/user";
import { requestLogout } from "../../actions/auth";
import Button from '@material-ui/core/Button';
import withWidth, { isWidthUp } from '@material-ui/core/withWidth'
import Typography from '@material-ui/core/Typography';
import { withRouter } from "next/router";
import ActiveLink from "./../atoms/Activelink";
import axios from 'axios';
import setAuthorizationHeader from "../../data/setAuthorizationHeader";
import getConfig from 'next/config'
import Router from 'next/router'
const styles = theme => ({
root: {
width: '100%',
position: 'relative',
zIndex: '999',
'& a': {
textDecoration: 'none'
}
},
toolbar: {
height: '64px',
},
grow: {
flexGrow: 1,
},
bar: {
},
menuButton: {
marginLeft: -12,
marginRight: 20,
@@ -65,240 +46,40 @@ const styles = theme => ({
menuLogo: {
cursor: 'pointer',
[theme.breakpoints.down('md')]: {
width: '200px'
width:'200px'
},
[theme.breakpoints.down('sm')]: {
width: '130px'
width:'100px'
},
},
menuAvatar: {
width: '2.5em',
borderRadius: '50%',
marginTop: theme.spacing(2),
marginLeft: theme.spacing(2),
},
menuUserName: {
color: theme.palette.menu.emailText,
fontSize: '1.3rem',
fontWeight: '500',
},
menuUserEmail: {
color: theme.palette.menu.emailText,
fontSize: '0.9rem',
fontWeight: '200',
},
darkDivider: {
background: 'whitesmoke',
opacity: '0.1',
},
List: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
height: '100%',
paddingTop: 0,
paddingBottom: 0,
'&>a:first-child': {
minHeight: '64px',
height: '64px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
title: {
display: 'none',
[theme.breakpoints.up('sm')]: {
display: 'block',
},
[theme.breakpoints.down('md')]: {
display: 'none',
},
marginRight: 15,
cursor: 'pointer'
},
sectionDesktop: {
display: 'none',
[theme.breakpoints.up('md')]: {
'&>a:first-child': {
height: '64px',
},
'&>a:first-child li': {
height: '64px',
alignItems: 'center',
},
display: 'flex',
},
},
sectionMobile: {
display: 'flex',
[theme.breakpoints.up('md')]: {
display: 'none',
},
},
fullList: {
width: 'auto',
cursor: 'pointer',
paddingBottom: 0
},
lightFullList: {
height: '100vh',
backgroundColor: theme.palette.background.default,
},
darkFullList: {
backgroundColor: theme.palette.background.dark,
},
lightMenuItem: {
color: theme.palette.menu.lightText,
textDecoration: 'none',
},
darkMenuItem: {
color: theme.palette.menu.darkText,
textDecoration: 'none',
},
darkMenuItemSpecific: {
'&:hover,&:active': {
color: theme.palette.primary.main,
}
},
links: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
height: '100%',
},
linkGroup: {
padding: theme.spacing(1.2, 0),
paddingLeft: 0,
},
videothequeLinkGroup: {
backgroundColor: theme.palette.background.videotheque,
},
blogLinkGroup: {
backgroundColor: theme.palette.background.blog,
},
recruteurLinkGroup: {
backgroundColor: theme.palette.background.recruteur,
},
rootListItem: {
padding: theme.spacing(1, 2),
cursor: 'pointer',
display: 'flex',
flexDirection: 'row',
alignItems: 'flex-start',
},
rootListItemIcon: {
padding: theme.spacing(1, 2),
cursor: 'pointer',
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
},
ListItemUserConnected: {
flexDirection: 'column',
},
ListItemText: {
fontSize: '1em',
},
icon: {
paddingRight: theme.spacing(2.5),
},
iconAccount: {
color: theme.palette.primary.dark,
},
title: {
color: theme.palette.secondary.main,
fontSize: '1.5em'
},
email: {
color: theme.palette.menu.emailText,
fontSize: '0.9em'
},
button: {
padding: theme.spacing(0.5, 1),
textTransform: 'inherit',
'& svg': {
width: '0.7em',
height: '0.7em',
},
},
active: {
'& span, & svg': {
color: theme.palette.primary.main + ' !important',
},
},
//DESKTOP PART
desktopMenuItem: {
[theme.breakpoints.down('md')]: {
padding: theme.spacing(0.4),
},
'& span.MuiTypography-root': {
fontSize: '0.8rem',
fontWeight: '500',
},
},
desktopMenuList: {
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: 0,
},
appBar:{
position:'fixed'
},
appBarDesktopSection: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
appBarDesktopSection1: {
padding: theme.spacing(0, 2),
height: '100%',
borderRight: 'solid 1px whitesmoke',
},
appBarDesktopSection2: {
width: '100%',
justifyContent: 'space-between',
padding: theme.spacing(0, 2),
'& ul': {
width: '95%',
},
'& ul>div': {
display: 'flex',
},
'& ul > div:nth-child(1) a span': {
color: theme.palette.primary.dark,
'&:hover, &:active': {
color: theme.palette.primary.main,
}
},
'& .MuiListItemText-root': {
padding: theme.spacing(0, 1),
[theme.breakpoints.down('md')]: {
padding: theme.spacing(0),
},
},
'& a:last-child .MuiButtonBase-root span': {
color: theme.palette.secondary.main,
},
},
appBarDesktopSection3: {
padding: theme.spacing(0, 2),
height: '100%',
backgroundColor: theme.palette.primary.dark,
'& a': {
display: 'flex',
alignItems: 'flex-end',
},
'& span, & svg': {
color: theme.palette.secondary.main,
},
},
toolbarDesktop: {
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
height: '64px',
},
desktopMenuButtonLogin: {
background: theme.palette.primary.main,
borderColor: theme.palette.primary.main,
},
rootListItemDesktop: {
[theme.breakpoints.up('md')]: {
padding: theme.spacing(1),
},
},
iconDesktop: {
paddingRight: theme.spacing(2.5),
[theme.breakpoints.up('md')]: {
paddingRight: 0,
},
cursor: 'pointer'
},
});
let urlEnv;
class Header extends React.Component {
state = {
@@ -306,51 +87,23 @@ class Header extends React.Component {
left: false,
bottom: false,
right: false,
toggle: true,
toggle: true
};
componentDidMount() {
}
toggleDrawer = (side, open) => () => {
this.setState({
[side]: open,
});
};
onRedirectAccount = e => {
urlEnv = (process.env.NODE_ENV !== 'production') ? '//localhost/app_dev.php' : process.env.SERVER_URL;
e.preventDefault();
var redirectAccountUrl = urlEnv + "/api/talent?bearer=" + localStorage.getItem("ttJWT");
window.open(redirectAccountUrl);
}
toggle = () => this.setState(state => ({ toggle: !state.toggle }))
chargerPage =(type)=> {
console.log(type);
//Router.replace(page);
sessionStorage.setItem(type+'_currentPage',1);
}
redirectionrecruteur=(props) => {
console.log("redirection recruteur")
localStorage.removeItem("ttJWT");
//this.openDialog()
props.requestLogout();
window.location.href = "https://recruteur.talentstube.com/";
}
render() {
const { classes } = this.props;
const { publicRuntimeConfig } = getConfig();
console.log("user",this.props.user)
return (
<div className={classes.root}>
<Drawer anchor="left" open={this.state.left} onClose={this.toggleDrawer('left', false)}>
@@ -360,82 +113,75 @@ class Header extends React.Component {
onClick={this.toggleDrawer('left', false)}
onKeyDown={this.toggleDrawer('left', false)}
>
<div className={classes.fullList + ' ' + classes.lightFullList}>
<List className={classes.List}>
<Link href="/" >
<a className={classes.darkMenuItem}><ListItem classes={{ root: classes.rootListItem }}>
<img alt="talents-tube" src='/statique/images/logos/TalentsTube_logo-color.svg' className={classes.menuLogo} />
<div className={classes.fullList}>
<List>
<Link href="/" prefetch >
<a><ListItem>
<img alt="talents-tube" src='/static/images/logos/Logo-header.svg' className={classes.menuLogo} />
</ListItem></a>
</Link>
<Divider />
<div className={classes.links}>
{/* Menu Accueil /Offres Entreprises */}
<div className={classes.linkGroup}>
<ActiveLink activeClassName={classes.active} href="/" >
<a className={classes.darkMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
<HomeIcon className={classes.icon} />
<ListItemText classes={{ primary: classes.ListItemText }} primary='Accueil'>
</ListItemText>
</ListItem></a>
</ActiveLink>
<ActiveLink activeClassName={classes.active} href="/Offres" >
<a className={classes.darkMenuItem + ' ' + classes.darkMenuItemSpecific}><ListItem classes={{ root: classes.rootListItemIcon }}>
<OfferIcon className={classes.icon} />
<ListItemText classes={{ primary: classes.ListItemText }} primary={`Offres d'emploi`}>
</ListItemText>
</ListItem></a>
</ActiveLink>
<ActiveLink activeClassName={classes.active} href="/Entreprises" >
<a className={classes.darkMenuItem + ' ' + classes.darkMenuItemSpecific}><ListItem classes={{ root: classes.rootListItemIcon }}>
<CompanyIcon className={classes.icon} />
<ListItemText classes={{ primary: classes.ListItemText }} primary='Nos entreprises'>
</ListItemText>
</ListItem></a>
</ActiveLink>
<ActiveLink activeClassName={classes.active} href="/Help" >
<a className={classes.darkMenuItem + ' ' + classes.darkMenuItemSpecific}><ListItem classes={{ root: classes.rootListItem }}>
<HelpIcon className={classes.icon} />
<ListItemText classes={{ primary: classes.ListItemText }} primary='Comment ça marche ?'>
</ListItemText>
</ListItem></a>
</ActiveLink>
<a className={classes.darkMenuItem + ' ' + classes.darkMenuItemSpecific} href="https://blog.talentstube.com/" target="_blank">
<ListItem classes={{ root: classes.rootListItem }}>
<NotesIcon className={classes.icon} />
<ListItemText classes={{ primary: classes.ListItemText }} primary='Blog'>
</ListItemText>
</ListItem>
</a>
</div>
{/* FIN Menu Accueil /Offres Entreprises */}
{/* Menu recruteur */}
<div>
{/* <div className={classes.blogLinkGroup}>
<a href={publicRuntimeConfig.blogUrl} className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
<NotesIcon className={classes.icon} />
<ListItemText classes={{ primary: classes.ListItemText }} primary='Blog'>
</ListItemText>
</ListItem>
</a>
</div> */}
<div className={classes.recruteurLinkGroup}>
<a href={publicRuntimeConfig.symphonyUrl } className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
<SupervisorAccountIcon className={classes.icon} />
<ListItemText classes={{ primary: classes.ListItemText }} primary='Recruteurs'>
</ListItemText>
</ListItem></a>
</div>
</div>
{/* FIN Menu recruteur*/}
<Link href="/" prefetch >
<a><ListItem>
</div>
<ListItemText primary='Accueil'>
</ListItemText>
</ListItem></a>
</Link>
<Link href="/Offres" prefetch >
<a><ListItem>
<ListItemText primary="Offres d'emploi">
</ListItemText>
</ListItem></a>
</Link>
<Link href="/Companies" prefetch >
<a><ListItem>
<ListItemText primary='Entreprises'>
</ListItemText>
</ListItem></a>
</Link>
<Link href="/help" prefetch >
<a><ListItem>
<ListItemText primary='Comment ça marche ?'>
</ListItemText>
</ListItem></a>
</Link>
<Divider />
<Link href="/" prefetch >
<a><ListItem>
<ListItemText primary='CV vidéothèque'>
</ListItemText>
</ListItem></a>
</Link>
<Link href="https://blog.talentstube.com" prefetch >
<a><ListItem>
<ListItemText primary='Blog'>
</ListItemText>
</ListItem></a>
</Link>
<Link href="/contact" prefetch >
<a><ListItem>
<ListItemText primary='Contact'>
</ListItemText>
</ListItem></a>
</Link>
<Divider />
<Link href="https://www.talentstube.com/faire-offre-emploi-video" prefetch >
<a><ListItem>
<ListItemText primary='Recruteurs'>
</ListItemText>
</ListItem></a>
</Link>
</List>
</div>
</div>
</Drawer>
@@ -446,268 +192,118 @@ class Header extends React.Component {
role="button"
onClick={this.toggleDrawer('right', false)}
onKeyDown={this.toggleDrawer('right', false)}
>
{!!this.props.loading &&
(<Loader />
)
}
>{!!this.props.loading &&
(<div className="alert alert-info"><CircularProgress color="secondary" />Chargement...</div>
)}
{!!!this.props.loading && !!!this.props.fetched
&&
<div className={classes.fullList + ' ' + classes.darkFullList}>
<div className={classes.fullList}>
<List>
<Link href="/" >
<a className={classes.darkMenuItem + ' cypFrontPage'}><ListItem classes={{ root: classes.rootListItemIcon }}>
<img alt="talents-tube" src='/statique/images/logos/TalentsTube_logo-blanc.svg' className={classes.menuLogo} />
<ListItem>
</ListItem>
<ListItem>
</ListItem>
<ListItem>
</ListItem>
<ListItem>
</ListItem>
<Divider />
<Link href="/login" prefetch >
<a><ListItem>
<ListItemText primary='Connexion'>
</ListItemText>
</ListItem></a>
</Link>
{/* TODO */}
<Link href="/login" prefetch >
<a><ListItem>
<Divider light={true} />
<div className={classes.linkGroup}>
<Link href="/Login" >
<a className={classes.lightMenuItem + ' cypConnexion'}><ListItem classes={{ root: classes.rootListItemIcon }} >
<PersonIcon className={classes.icon} />
<ListItemText classes={{ primary: classes.ListItemText }} primary='Connexion'>
</ListItemText>
</ListItem></a>
</Link>
{/* TODO */}
<Link href="/Inscription" >
<a className={classes.lightMenuItem + ' cypRegister'}><ListItem classes={{ primary: classes.ListItemText }} classes={{ root: classes.rootListItem }}>
<PersonAddIcon className={classes.icon} />
<ListItemText primary='Inscription'>
</ListItemText>
</ListItem></a>
</Link>
</div>
<Divider light={true} />
<div className={classes.linkGroup}>
{/* <a href={publicRuntimeConfig.symphonyUrl + "/"} className={classes.lightMenuItem}><ListItem classes={{ primary: classes.ListItemText }} classes={{ root: classes.rootListItemIcon }}>
<WorkOutlineIcon className={classes.icon} />
<ListItemText primary='Connexion recruteurs'>
</ListItemText>
</ListItem>
</a> */}
</div>
</List>
</div>
}
{!!!this.props.loading && !!this.props.fetched &&
<Fragment>
{this.props.user.picture ?
<img alt="talents-tube" src={publicRuntimeConfig.symphonyUrl +publicRuntimeConfig.postedContentUrl+ this.props.user.picture} className={classes.menuAvatar} />
:
<img alt="talents-tube" src='/static/images/default/account-avatar-default.svg' className={classes.menuAvatar} />
}
<ListItem classes={{ root: classes.rootListItem }} className={classes.ListItemUserConnected}>
<Typography gutterBottom component="h1" className={classes.menuUserName}>
{this.props.user.firstname + " " + this.props.user.lastname}
</Typography>
<Typography gutterBottom component="h3" className={classes.menuUserEmail} >
{this.props.user.email}
</Typography>
</ListItem>
<Divider className={classes.darkDivider} />
{this.props.user.type=="TALENT"
?
<div>
<Link href="/Candidatures" >
<a className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
<FolderSharedIcon className={classes.icon} />
<ListItemText primary='Mes candidatures'>
</ListItemText>
</ListItem></a>
</Link>
<Link href="/profileStep" >
<a className={classes.lightMenuItem}>
<ListItem classes={{ root: classes.rootListItemIcon }}>
<AccountCircleIcon className={classes.icon} />
<ListItemText primary='Mon profil'>
</ListItemText>
</ListItem>
</a>
</Link>
<Link href="/Parametres" >
<a className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
<SettingsIcon className={classes.icon} />
<ListItemText primary='Paramètres'>
</ListItemText>
</ListItem></a>
</Link>
</div>
:
this.redirectionrecruteur(this.props)
// <div>
// <a href={publicRuntimeConfig.symphonyUrl + "/"} className={classes.lightMenuItem}>
// <ListItem classes={{ root: classes.rootListItemIcon }}>
// <SettingsIcon className={classes.icon} />
// <ListItemText primary='Espace recruteur'>
// </ListItemText>
// </ListItem></a>
// </div>
}
<Link href="/" >
<a onClick={() => {
localStorage.removeItem("ttJWT");
return this.props.requestLogout();
}} className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
<PowerSettingsNewIcon className={classes.icon} />
<ListItemText primary='Déconnexion'>
<ListItemText primary='Inscription'>
</ListItemText>
</ListItem></a>
</Link>
<Divider />
<Link href="https://www.talentstube.com/faire-offre-emploi-video" >
<a><ListItem>
<ListItemText primary='Espace recruteurs'>
</ListItemText>
</ListItem></a>
</Link>
</List>
</div>}
{!!!this.props.loading && !!this.props.fetched &&
<Fragment>
<ListItem>
{this.props.user.firstname}
{this.props.user.lastname}
{this.props.user.email}
</ListItem>
<Divider />
{/* TODO:real links */}
<Link href="/Candidatures" prefetch >
<a><ListItem>
<ListItemText primary='Mes candidatures'>
</ListItemText>
</ListItem></a>
</Link>
<Link href="/help" prefetch >
<a><ListItem>
<ListItemText primary='Mon compte'>
</ListItemText>
</ListItem></a>
</Link>
<Link href="/help" prefetch >
<a><ListItem>
<ListItemText primary='Paramètres'>
</ListItemText>
</ListItem></a>
</Link>
<ListItem>
<Button
variant="contained"
color="primary"
className={classes.button}
onClick={() => this.props.requestLogout()}>Déconnexion</Button>
</ListItem>
</Fragment>
}
</div>
</Drawer>
<AppBar position="static" className={classes.appBar}>
<Toolbar>
<IconButton className={classes.menuButton} onClick={this.toggleDrawer('left', true)}
color="inherit" aria-label="Open drawer">
<MenuIcon />
</IconButton>
<div className={classes.grow} />
{isWidthUp('md', this.props.width) ?
(<AppBar position="static" className={classes.appBar}>
<Toolbar disableGutters={true} className={classes.toolbarDesktop}>
<section className={classes.appBarDesktopSection + ' ' + classes.appBarDesktopSection1}>
<Link href="/" >
<a className={classes.darkMenuItem}>
<ListItem classes={{ root: classes.rootListItemDesktop }}>
<img alt="talents-tube" src='/statique/images/logos/TalentsTube_logo-color.svg' className={classes.desktopMenuLogo} />
</ListItem>
</a>
</Link>
</section>
<section className={classes.appBarDesktopSection + ' ' + classes.appBarDesktopSection2}>
<IconButton className={classes.menuButton} onClick={this.toggleDrawer('left', true)}
color="inherit" aria-label="Open drawer">
<MenuIcon />
</IconButton>
<img alt="talents-tube" src='/static/images/logos/Logo-header.svg' className={classes.menuLogo} />
<List className={classes.desktopMenuList}>
<div>
<ActiveLink activeClassName={classes.active} href="/Offres" >
<a className={classes.desktopMenuItem} >
<ListItemText primary="Offres d'emploi">
</ListItemText>
</a>
</ActiveLink>
<ActiveLink activeClassName={classes.active} href="/Entreprises" >
<a className={classes.desktopMenuItem}>
<ListItemText primary='Nos entreprises'>
</ListItemText>
</a>
</ActiveLink>
<ActiveLink activeClassName={classes.active} href="/Help" >
<a className={classes.desktopMenuItem}>
<ListItemText primary='Comment ça marche ?'>
</ListItemText>
</a>
</ActiveLink>
<a className={classes.desktopMenuItem} target="_blank" href="https://blog.talentstube.com/">
<ListItemText primary='Blog'>
</ListItemText>
</a>
</div>
<div>
{!!!this.props.loading && !!!this.props.fetched &&
<Fragment>
<Link href="/Inscription" >
<a className={classes.desktopMenuItem}>
<ListItem classes={{ root: classes.rootListItemDesktop }}>
<Button
variant="outlined"
className={classes.button + ' ' + classes.desktopMenuButtonRegister}>
<PersonAddIcon className={classes.iconDesktop} />
<ListItemText classes={{ primary: classes.ListItemText }} primary='Inscription'></ListItemText>
</Button >
</ListItem>
</a>
</Link>
<Link href="/Login" >
<a className={classes.desktopMenuItem}>
<ListItem classes={{ root: classes.rootListItemDesktop }}>
<Button
variant="outlined"
className={classes.button + ' ' + classes.desktopMenuButtonLogin}>
<PersonIcon className={classes.iconDesktop} />
<ListItemText classes={{ primary: classes.ListItemText }} primary='Connexion'></ListItemText>
</Button >
</ListItem>
</a>
</Link>
</Fragment>
}
{!!!this.props.loading && !!this.props.fetched &&
<IconButton
edge="end"
aria-label="Profile"
aria-controls={'primary-search-account-menu'}
aria-haspopup="true"
onClick={this.toggleDrawer('right', true)}
className={classes.iconAccount + ' cypConnexionMenu'}
>
<AccountCircleOutlinedIcon />
</IconButton>
}
</div>
</List>
</section>
{/* <section className={classes.appBarDesktopSection + ' ' + classes.appBarDesktopSection3}>
<a href={publicRuntimeConfig.symphonyUrl + "/"} className={classes.desktopMenuItem}>
<ListItemText primary='Espace recruteurs'>
</ListItemText>
<ArrowForward className={classes.icon} />
</a>
</section> */}
</Toolbar>
</AppBar>)
:
(
<AppBar position="static" className={classes.appBar}>
<Toolbar className={classes.toolbar}>
<IconButton className={classes.menuButton} onClick={this.toggleDrawer('left', true)}
color="inherit" role="button">
<MenuIcon />
</IconButton>
<div className={classes.grow} />
<Link href="/" >
<a><img alt="talents-tube" src='/statique/images/logos/TalentsTube_logo-color.svg' className={classes.menuLogo} /></a>
</Link>
<div className={classes.grow} />
<IconButton
edge="end"
aria-label="Profile"
aria-controls={'primary-search-account-menu'}
aria-haspopup="true"
onClick={this.toggleDrawer('right', true)}
className={classes.iconAccount + ' cypConnexionMenu'}
>
<AccountCircleOutlinedIcon />
</IconButton>
</Toolbar>
</AppBar>
)}
<div className={classes.grow} />
<IconButton
edge="end"
aria-label="Profile"
aria-controls={'primary-search-account-menu'}
aria-haspopup="true"
onClick={this.toggleDrawer('right', true)}
color="inherit"
>
<AccountCircle />
</IconButton>
</Toolbar>
</AppBar>
</div >
);
}
}
Header.propTypes = {
classes: PropTypes.object.isRequired,
};
function mapStateToProps(state) {
return {
user: state.user,
@@ -715,4 +311,5 @@ function mapStateToProps(state) {
loading: !!state.user.loading
};
}
export default (connect(mapStateToProps, { fetchCurrentUserRequest, requestLogout })(withStyles(styles)(withWidth()(Header))));
export default withStyles(styles)(connect(mapStateToProps, { fetchCurrentUserRequest, requestLogout })(Header));
@@ -1,634 +0,0 @@
import React, { Fragment, Children } from 'react';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import IconButton from '@material-ui/core/IconButton';
import { withStyles, getMuiTheme } from '@material-ui/core/styles';
import MenuIcon from '@material-ui/icons/Menu';
import Link from 'next/link'
import Drawer from '@material-ui/core/Drawer';
import Divider from '@material-ui/core/Divider';
import HomeIcon from '@material-ui/icons/HomeOutlined';
import OfferIcon from '@material-ui/icons/LocalOfferOutlined';
import CompanyIcon from '@material-ui/icons/DomainOutlined';
import HelpIcon from '@material-ui/icons/HelpOutline';
import VideoIcon from '@material-ui/icons/OndemandVideoOutlined';
import NotesIcon from '@material-ui/icons/NotesOutlined';
import SupervisorAccountIcon from '@material-ui/icons/SupervisorAccount';
import PersonIcon from '@material-ui/icons/Person';
import PersonAddIcon from '@material-ui/icons/PersonAdd';
import WorkOutlineIcon from '@material-ui/icons/WorkOutline';
import AccountCircleOutlinedIcon from '@material-ui/icons/AccountCircleOutlined';
import FolderSharedIcon from '@material-ui/icons/FolderShared';
import AccountCircleIcon from '@material-ui/icons/AccountCircle';
import PermContactCalendar from '@material-ui/icons/PermContactCalendar';
import VideoCam from '@material-ui/icons/Videocam';
import SettingsIcon from '@material-ui/icons/Settings';
import PowerSettingsNewIcon from '@material-ui/icons/PowerSettingsNew';
import ArrowForward from '@material-ui/icons/ArrowForward';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import { ListItemText } from '@material-ui/core';
import Loader from '../templates/loader'
import { connect } from 'react-redux'
import { fetchCurrentUserRequest } from "../../actions/user";
import { requestLogout } from "../../actions/auth";
import Button from '@material-ui/core/Button';
import withWidth, { isWidthUp } from '@material-ui/core/withWidth'
import Typography from '@material-ui/core/Typography';
import { withRouter } from "next/router";
import ActiveLink from "../atoms/Activelink";
import axios from 'axios';
import setAuthorizationHeader from "../../data/setAuthorizationHeader";
import getConfig from 'next/config'
import Router from 'next/router'
import ButtonBase from "@material-ui/core/ButtonBase";
import ArrowLeft from '@material-ui/icons/KeyboardArrowLeft';
import LoadingBar from 'react-redux-loading-bar'
const styles = theme => ({
root: {
width: '100%',
position: 'relative',
zIndex: '999',
'& a': {
textDecoration: 'none'
}
},
toolbar: {
height: '64px',
},
grow: {
flexGrow: 1,
},
menuButton: {
marginLeft: -12,
marginRight: 20,
display: 'block'
},
menuLogo: {
cursor: 'pointer',
[theme.breakpoints.down('md')]: {
width: '200px'
},
[theme.breakpoints.down('sm')]: {
width: '130px'
},
},
menuAvatar: {
width: '2.5em',
borderRadius: '50%',
marginTop: theme.spacing(2),
marginLeft: theme.spacing(2),
},
menuUserName: {
color: theme.palette.menu.emailText,
fontSize: '1.3rem',
fontWeight: '500',
},
menuUserEmail: {
color: theme.palette.menu.emailText,
fontSize: '0.9rem',
fontWeight: '200',
},
darkDivider: {
background: 'whitesmoke',
opacity: '0.1',
},
List: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
height: '100%',
paddingTop: 0,
paddingBottom: 0,
'&>a:first-child': {
minHeight: '64px',
height: '64px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
[theme.breakpoints.up('md')]: {
'&>a:first-child': {
height: '64px',
},
'&>a:first-child li': {
height: '64px',
alignItems: 'center',
},
},
},
fullList: {
width: 'auto',
cursor: 'pointer',
paddingBottom: 0
},
lightFullList: {
height: '100vh',
backgroundColor: theme.palette.background.default,
},
darkFullList: {
backgroundColor: theme.palette.background.dark,
},
lightMenuItem: {
color: theme.palette.menu.lightText,
textDecoration: 'none',
},
darkMenuItem: {
color: theme.palette.menu.darkText,
textDecoration: 'none',
},
darkMenuItemSpecific: {
'&:hover,&:active': {
color: theme.palette.primary.main,
}
},
links: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
height: '100%',
},
linkGroup: {
padding: theme.spacing(1.2, 0),
paddingLeft: 0,
},
videothequeLinkGroup: {
backgroundColor: theme.palette.background.videotheque,
},
blogLinkGroup: {
backgroundColor: theme.palette.background.blog,
},
recruteurLinkGroup: {
backgroundColor: theme.palette.background.recruteur,
},
rootListItem: {
padding: theme.spacing(1, 2),
cursor: 'pointer',
display: 'flex',
flexDirection: 'row',
alignItems: 'flex-start',
},
rootListItemIcon: {
padding: theme.spacing(1, 2),
cursor: 'pointer',
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
},
ListItemUserConnected: {
flexDirection: 'column',
},
ListItemText: {
fontSize: '1em',
},
icon: {
paddingRight: theme.spacing(2.5),
},
iconAccount: {
color: theme.palette.primary.dark,
},
title: {
color: theme.palette.secondary.main,
fontSize: '1.5em'
},
email: {
color: theme.palette.menu.emailText,
fontSize: '0.9em'
},
button: {
padding: theme.spacing(0.5, 1),
textTransform: 'inherit',
'& svg': {
width: '0.7em',
height: '0.7em',
},
},
active: {
'& span, & svg': {
color: theme.palette.primary.main + ' !important',
},
},
//DESKTOP PART
desktopMenuItem: {
[theme.breakpoints.down('md')]: {
padding: theme.spacing(0.4),
},
'& span.MuiTypography-root': {
fontSize: '0.8rem',
fontWeight: '500',
},
},
desktopMenuList: {
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: 0,
},
appBar:{
position:'fixed'
},
appBarDesktopSection: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
appBarDesktopSection1: {
padding: theme.spacing(0, 2),
height: '100%',
borderRight: 'solid 1px whitesmoke',
},
appBarDesktopSection2: {
width: '100%',
justifyContent: 'space-between',
padding: theme.spacing(0, 2),
'& ul': {
width: '95%',
},
'& ul>div': {
display: 'flex',
},
'& ul > div:nth-child(1) a span': {
color: theme.palette.primary.dark,
'&:hover, &:active': {
color: theme.palette.primary.main,
}
},
'& .MuiListItemText-root': {
padding: theme.spacing(0, 1),
[theme.breakpoints.down('md')]: {
padding: theme.spacing(0),
},
},
'& a:last-child .MuiButtonBase-root span': {
color: theme.palette.secondary.main,
},
},
appBarDesktopSection3: {
padding: theme.spacing(0, 2),
height: '100%',
backgroundColor: theme.palette.primary.dark,
'& a': {
display: 'flex',
alignItems: 'flex-end',
},
'& span, & svg': {
color: theme.palette.secondary.main,
},
},
toolbarDesktop: {
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
height: '64px',
},
desktopMenuButtonLogin: {
background: theme.palette.primary.main,
borderColor: theme.palette.primary.main,
},
rootListItemDesktop: {
[theme.breakpoints.up('md')]: {
padding: theme.spacing(1),
},
},
iconDesktop: {
paddingRight: theme.spacing(2.5),
[theme.breakpoints.up('md')]: {
paddingRight: 0,
},
},
});
let urlEnv;
class HeaderPersonnalise extends React.Component {
state = {
top: false,
left: false,
bottom: false,
right: false,
toggle: true
};
redirectionrecruteur=(props) => {
console.log("redirection recruteur")
localStorage.removeItem("ttJWT");
//this.openDialog()
props.requestLogout();
window.location.href = "https://recruteur.talentstube.com/";
}
componentDidMount() {
}
toggleDrawer = (side, open) => () => {
this.setState({
[side]: open,
});
};
onRedirectAccount = e => {
urlEnv = (process.env.NODE_ENV !== 'production') ? '//localhost/app_dev.php' : process.env.SERVER_URL;
e.preventDefault();
var redirectAccountUrl = urlEnv + "/api/talent?bearer=" + localStorage.getItem("ttJWT");
window.open(redirectAccountUrl);
}
toggle = () => this.setState(state => ({ toggle: !state.toggle }))
chargerPage =(type)=> {
console.log(type);
//Router.replace(page);
sessionStorage.setItem(type+'_currentPage',1);
}
render() {
const { classes } = this.props;
const { publicRuntimeConfig } = getConfig();
return (
<div className={classes.root}>
<Drawer anchor="right" open={this.state.right} onClose={this.toggleDrawer('right', false)}>
<div
tabIndex={0}
role="button"
onClick={this.toggleDrawer('right', false)}
onKeyDown={this.toggleDrawer('right', false)}
>{!!this.props.loading &&
(<Loader />
)}
{!!!this.props.loading && !!!this.props.fetched
&&
<div className={classes.fullList + ' ' + classes.darkFullList}>
<List>
<Link href="/" >
<a className={classes.darkMenuItem + ' cypFrontPage'}><ListItem classes={{ root: classes.rootListItemIcon }}>
<img alt="talents-tube" src='/statique/images/logos/TalentsTube_logo-blanc.svg' className={classes.menuLogo} />
</ListItem></a>
</Link>
<Divider light={true} />
<div className={classes.linkGroup}>
<Link href="/Login" >
<a className={classes.lightMenuItem + ' cypConnexion'}><ListItem classes={{ root: classes.rootListItemIcon }} >
<PersonIcon className={classes.icon} />
<ListItemText classes={{ primary: classes.ListItemText }} primary='Connexion'>
</ListItemText>
</ListItem></a>
</Link>
{/* TODO */}
<Link href="/Inscription" >
<a className={classes.lightMenuItem + ' cypRegister'}><ListItem classes={{ primary: classes.ListItemText }} classes={{ root: classes.rootListItem }}>
<PersonAddIcon className={classes.icon} />
<ListItemText primary='Inscription'>
</ListItemText>
</ListItem></a>
</Link>
</div>
<Divider light={true} />
<div className={classes.linkGroup}>
{/* <a href={publicRuntimeConfig.symphonyUrl + "/"} className={classes.lightMenuItem}><ListItem classes={{ primary: classes.ListItemText }} classes={{ root: classes.rootListItemIcon }}>
<WorkOutlineIcon className={classes.icon} />
<ListItemText primary='Connexion recruteurs'>
</ListItemText>
</ListItem>
</a> */}
</div>
</List>
</div>}
{!!!this.props.loading && !!this.props.fetched &&
<Fragment>
{this.props.user.picture ?
<img alt="talents-tube" src={publicRuntimeConfig.symphonyUrl +publicRuntimeConfig.postedContentUrl+ this.props.user.picture} className={classes.menuAvatar} />
:
<img alt="talents-tube" src='/static/images/default/account-avatar-default.svg' className={classes.menuAvatar} />
}
<ListItem classes={{ root: classes.rootListItem }} className={classes.ListItemUserConnected}>
<Typography gutterBottom component="h1" className={classes.menuUserName}>
{this.props.user.firstname + " " + this.props.user.lastname}
</Typography>
<Typography gutterBottom component="h3" className={classes.menuUserEmail} >
{this.props.user.email}
</Typography>
</ListItem>
<Divider className={classes.darkDivider} />
{this.props.user.type=="TALENT"
?
<div>
<Link href="/Candidatures" >
<a className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
<FolderSharedIcon className={classes.icon} />
<ListItemText primary='Mes candidatures'>
</ListItemText>
</ListItem></a>
</Link>
<Link href="/profileStep" >
<a className={classes.lightMenuItem}>
<ListItem classes={{ root: classes.rootListItemIcon }}>
<AccountCircleIcon className={classes.icon} />
<ListItemText primary='Mon profil'>
</ListItemText>
</ListItem>
</a>
</Link>
<Link href="/Parametres" >
<a className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
<SettingsIcon className={classes.icon} />
<ListItemText primary='Paramètres'>
</ListItemText>
</ListItem></a>
</Link>
</div>
:
this.redirectionrecruteur(this.props)
// <div>
// <a href={publicRuntimeConfig.symphonyUrl + "/"} className={classes.lightMenuItem}>
// <ListItem classes={{ root: classes.rootListItemIcon }}>
// <SettingsIcon className={classes.icon} />
// <ListItemText primary='Espace recruteur'>
// </ListItemText>
// </ListItem></a>
// </div>
}
<Link href="/" >
<a onClick={() => {
localStorage.removeItem("ttJWT");
return this.props.requestLogout();
}} className={classes.lightMenuItem}><ListItem classes={{ root: classes.rootListItemIcon }}>
<PowerSettingsNewIcon className={classes.icon} />
<ListItemText primary='Déconnexion'>
</ListItemText>
</ListItem></a>
</Link>
</Fragment>
}
</div>
</Drawer>
{isWidthUp('md', this.props.width) ?
(<AppBar position="static" className={classes.appBar}>
<Toolbar disableGutters={true} className={classes.toolbarDesktop}>
<section className={classes.appBarDesktopSection + ' ' + classes.appBarDesktopSection1}>
<Link href="/" >
<a className={classes.darkMenuItem}>
<ListItem classes={{ root: classes.rootListItemDesktop }}>
<img alt="talents-tube" src='/statique/images/logos/TalentsTube_logo-color.svg' className={classes.desktopMenuLogo} />
</ListItem>
</a>
</Link>
</section>
<section className={classes.appBarDesktopSection + ' ' + classes.appBarDesktopSection2}>
{/* <IconButton className={classes.menuButton} onClick={this.toggleDrawer('left', true)}
color="inherit" aria-label="Open drawer">
<MenuIcon />
</IconButton> */}
<List className={classes.desktopMenuList}>
<div>
<ActiveLink activeClassName={classes.active} href="/Offres" >
<a className={classes.desktopMenuItem} >
<ListItemText primary="Offres d'emploi">
</ListItemText>
</a>
</ActiveLink>
<ActiveLink activeClassName={classes.active} href="/Entreprises" >
<a className={classes.desktopMenuItem}>
<ListItemText primary='Nos entreprises'>
</ListItemText>
</a>
</ActiveLink>
<ActiveLink activeClassName={classes.active} href="/Help" >
<a className={classes.desktopMenuItem}>
<ListItemText primary='Comment ça marche ?'>
</ListItemText>
</a>
</ActiveLink>
<a className={classes.desktopMenuItem} target="_blank" href="https://blog.talentstube.com/">
<ListItemText primary='Blog'>
</ListItemText>
</a>
</div>
<div>
{!!!this.props.loading && !!!this.props.fetched &&
<Fragment>
<Link href="/Inscription" >
<a className={classes.desktopMenuItem}>
<ListItem classes={{ root: classes.rootListItemDesktop }}>
<Button
variant="outlined"
className={classes.button + ' ' + classes.desktopMenuButtonRegister}>
<PersonAddIcon className={classes.iconDesktop} />
<ListItemText classes={{ primary: classes.ListItemText }} primary='Inscription'></ListItemText>
</Button >
</ListItem>
</a>
</Link>
<Link href="/Login" >
<a className={classes.desktopMenuItem}>
<ListItem classes={{ root: classes.rootListItemDesktop }}>
<Button
variant="outlined"
className={classes.button + ' ' + classes.desktopMenuButtonLogin}>
<PersonIcon className={classes.iconDesktop} />
<ListItemText classes={{ primary: classes.ListItemText }} primary='Connexion'></ListItemText>
</Button >
</ListItem>
</a>
</Link>
</Fragment>
}
{!!!this.props.loading && !!this.props.fetched &&
<IconButton
edge="end"
aria-label="Profile"
aria-controls={'primary-search-account-menu'}
aria-haspopup="true"
onClick={this.toggleDrawer('right', true)}
className={classes.iconAccount + ' cypConnexionMenu'}
>
<AccountCircleOutlinedIcon />
</IconButton>
}
</div>
</List>
</section>
{/* <section className={classes.appBarDesktopSection + ' ' + classes.appBarDesktopSection3}>
<a href={publicRuntimeConfig.symphonyUrl + "/"} className={classes.desktopMenuItem}>
<ListItemText primary='Espace recruteurs'>
</ListItemText>
<ArrowForward className={classes.icon} />
</a>
</section> */}
</Toolbar>
</AppBar>)
:
(
<AppBar position="static" className={classes.appBar}>
<Toolbar className={classes.toolbar}>
{/* <IconButton className={classes.menuButton} onClick={this.toggleDrawer('left', true)}
color="inherit" role="button">
<MenuIcon />
</IconButton> */}
<ButtonBase name='back'
focusRipple
className={classes.back}
focusVisibleClassName={classes.focusVisible}
onClick={() => Router.push("/"+this.props.retour)}>
<ArrowLeft color="primary" classes={{ root: classes.icon }}></ArrowLeft>
</ButtonBase>
<div className={classes.grow} />
<Link href="/" >
<a><img alt="talents-tube" src='/statique/images/logos/TalentsTube_logo-color.svg' className={classes.menuLogo} /></a>
</Link>
<div className={classes.grow} />
<IconButton
edge="end"
aria-label="Profile"
aria-controls={'primary-search-account-menu'}
aria-haspopup="true"
onClick={this.toggleDrawer('right', true)}
className={classes.iconAccount + ' cypConnexionMenu'}
>
<AccountCircleOutlinedIcon />
</IconButton>
</Toolbar>
</AppBar>
)}
</div >
);
}
}
function mapStateToProps(state) {
return {
user: state.user,
fetched: !!state.user.fetched,
loading: !!state.user.loading
};
}
export default (connect(mapStateToProps, { fetchCurrentUserRequest, requestLogout })(withStyles(styles)(withWidth()(HeaderPersonnalise))));
+20 -103
View File
@@ -2,35 +2,22 @@ import React, { Component, Fragment } from 'react'
import GridList from '@material-ui/core/GridList';
import GridListTile from '@material-ui/core/GridListTile';
import { withStyles } from '@material-ui/core/styles';
import withWidth, { isWidthUp } from '@material-ui/core/withWidth'
import ArrowLeft from '@material-ui/icons/ArrowBackIosSharp';
import ArrowRight from '@material-ui/icons/ArrowForwardIosSharp';
import Hidden from '@material-ui/core/Hidden';
import Tile from './Tile';
const styles = theme => ({
root: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
flexWrap: 'wrap',
justifyContent: 'space-around',
overflow: 'hidden',
width: '100%',
},
rootGridList: {
margin: '0 !important',
backgroundColor: theme.palette.background.paper,
},
gridList: {
position: 'relative',
flexWrap: 'nowrap',
scrollBehavior: 'smooth',
width: '100%',
// Promote the list into his own layer on Chrome. This cost memory but helps keeping high FPS.
transform: 'translateZ(0)',
marginBottom: theme.spacing(4),
scrollbarWidth: 'none',
'&::-webkit-scrollbar': {
width: 0,
}
height: '100%',
},
gridListTile: {
display: 'flex',
@@ -38,114 +25,44 @@ const styles = theme => ({
alignItems: 'center',
justifyContent: 'center',
height: '100% !important',
//margin: '0 3vw',
padding: '16px !important',
[theme.breakpoints.up('md')]: {
margin: '0',
paddingTop: '5vh',
'&:first-child': {
marginLeft: '3vw',
},
},
rootGridListTile: {
margin: '3vw',
},
tile: {
width: '100% !important',
overflow: 'visible !important',
},
anchor: {
width: '100% !important',
position: 'absolute',
left: '16px',
right: '16px',
top: '-200px',
visibility: 'hidden',
},
anchorPrevious: {
left: '-16px',
},
anchorNext: {
left: '16px',
},
icon: {
width: '0.9em',
height: '0.9em',
padding: theme.spacing(1.5),
color: theme.palette.secondary.main,
background: theme.palette.primary.dark,
borderRadius: '50%',
},
dNone: {
visibility: 'hidden',
}
});
class HorizontalScroller extends Component {
state = {
defaultIndex: 2,
direction: '',
}
handlePrevious = () => {
this.setState({ direction: 'previous' })
if (this.state.defaultIndex == 8 || this.state.defaultIndex == 5) {
this.setState({ defaultIndex: this.state.defaultIndex - 5 })
}
if (this.state.defaultIndex == 3) {
this.setState({ defaultIndex: this.state.defaultIndex - 3 })
}
else if (this.state.defaultIndex == 0) {
this.setState({ defaultIndex: this.state.defaultIndex + 8 })
}
}
handleNext = () => {
this.setState({ direction: 'next' })
if (this.state.defaultIndex == 6 || this.state.defaultIndex == 7 || this.state.defaultIndex == 8) {
this.setState({ defaultIndex: 0 })
}
else if (this.state.defaultIndex == 0 || this.state.defaultIndex == 3) {
this.setState({ defaultIndex: this.state.defaultIndex + 5 })
}
else if (this.state.defaultIndex < 6) {
this.setState({ defaultIndex: this.state.defaultIndex + 3 })
}
}
render() {
const { classes, type } = this.props
const { defaultIndex } = this.state
const children = (tile) => React.Children.map(this.props.children, child => {
const { classes } = this.props
const children =(tile)=> React.Children.map(this.props.children, child => {
return React.cloneElement(child, {
tile
});
});
});
return (
<div className={classes.root}> {/* Ne pas mettre de Fragment */}
<Hidden smDown>
<a className={(defaultIndex < 3) ? classes.dNone : ''} onClick={this.handlePrevious} href={'#' + type + defaultIndex}><ArrowLeft classes={{ root: classes.icon }}></ArrowLeft></a>
</Hidden>
<GridList className={classes.gridList} cols={isWidthUp('md', this.props.width) ? 3 : isWidthUp('sm', this.props.width) ? 2.4 : 1.15} classes={{ root: classes.rootGridList }}>
{this.props.data && this.props.data.map((tile, index) => (
<GridListTile className={classes.gridListTile} classes={{ root: classes.rootGridListTile, tile: classes.tile }} key={index}>
<Tile rowData={tile} key={index}>
{(this.state.direction == 'previous') ? (<a id={type + index} className={classes.anchor + ' ' + classes.anchorPrevious}></a>) : (<a id={type + index} className={classes.anchor + ' ' + classes.anchorNext}></a>)
}
{children(tile)}
<div> {/* Ne pas mettre de Fragment */}
<GridList className={classes.gridList} cols={1.2}>
{this.props.data.map(tile => (
<GridListTile className={classes.gridListTile} classes={{ root: classes.rootGridListTile, tile: classes.tile }} key={tile.title}>
<Tile rowData={tile}>
{ children(tile) }
</Tile>
</GridListTile>
))}
</GridList>
<Hidden smDown>
<a className={(defaultIndex > 5) ? classes.dNone : ''} onClick={this.handleNext} href={'#' + type + defaultIndex}><ArrowRight classes={{ root: classes.icon }}></ArrowRight></a>
</Hidden>
</div>
)
}
}
export default withStyles(styles)(withWidth()(HorizontalScroller))
export default withStyles(styles)(HorizontalScroller)
@@ -1,179 +1,34 @@
import React, { Component, Fragment } from 'react';
import { connect } from "react-redux";
import Validator from "validator";
import { subscribeToNewsletterRequest } from "../../actions/user";
import React, { Component } from 'react'
import { Typography, Button } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import _ from "lodash";
import SendIcon from '@material-ui/icons/Send';
import TextField from '@material-ui/core/TextField';
import Snack from '../atoms/snack'
import TextField from '@material-ui/core/TextField';
const styles = theme => ({
root: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
[theme.breakpoints.up('sm')]: {
flexDirection: 'row',
},
textField: {
textAlign: 'center',
justifyContent: 'center',
},
text: {
fontSize: '1.2em',
fontWeight: '600',
paddingRight: theme.spacing(2),
paddingBottom: theme.spacing(3),
'& span': {
color: theme.palette.primary.main
},
[theme.breakpoints.up('sm')]: {
width: '25%',
paddingBottom: 0,
},
},
textField: {
textAlign: 'center',
justifyContent: 'center',
margin: 0,
'& input': {
backgroundColor: theme.palette.background.grey,
minWidth: '65vw',
[theme.breakpoints.up('sm')]: {
minWidth: 'inherit',
},
}
},
button: {
padding: theme.spacing(2, 0),
borderBottomLeftRadius: 0,
borderTopLeftRadius: 0,
boxShadown: '0px',
backgroundColor: theme.palette.primary.dark,
},
sendIcon: {
fill: theme.palette.background.grey,
},
newsletterForm: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: theme.palette.background.grey,
margin: theme.spacing(0, 4),
[theme.breakpoints.up('sm')]: {
width: 'max-content',
},
},
})
class NewsLetterRegistration extends Component {
state = {
data: {
email: "",
},
success: false,
errors: { message: "" },
loading: false,
tabIndex: 0,
openSnack: false
};
UNSAFE_componentWillReceiveProps(nextProps) {
this.setState({
errors: !!!nextProps.errors ? { errors: { message: "" } } : nextProps.errors,
loading: nextProps.loading,
success: nextProps.success,
openSnack: !_.isEmpty(nextProps.errors) || nextProps.success
})
}
onChange = e =>
this.setState({
data: { ...this.state.data, [e.target.name]: e.target.value }
});
onSubmit = e => {
e.preventDefault();
const errors = this.validate(this.state.data);
this.setState({ errors });
if (Object.keys(errors).length === 0) {
this.props.subscribeToNewsletterRequest(this.state.data)
}
};
submit = data => { this.props.login(data) }
validate = data => {
const errors = {};
if (!Validator.isEmail(data.email)) errors.email = "Invalid email";
return errors;
};
handleClose = e =>
this.setState({
openSnack: false
});
render() {
const { classes } = this.props;
const { data, success, errors, loading, openSnack } = this.state;
let {classes} = this.props
return (
<section className={classes.root}>
<Typography
gutterBottom
component="h3"
className={classes.text}
>
Recevez les dernières nouvelles de <span>Talents Tube</span> par e-mail
<div>
<Typography gutterBottom component="h3">
Recevez les dernières nouvelles de Talents Tube par e-mail
</Typography>
<form className={classes.newsletterForm} onSubmit={this.onSubmit}>
<TextField
id="outlined-with-placeholder"
disabled={loading}
label="Newsletter"
name="email"
value={data.email}
onChange={this.onChange}
type="email"
placeholder="exemple@gmail.com"
className={classes.textField}
InputLabelProps={{
shrink: true,
}}
margin="dense"
variant="filled"
/>
<Button type="submit"
name="registerToNewsletter"
disabled={loading}
variant="contained"
className={classes.button}
>
<SendIcon className={classes.sendIcon}/>
</Button >
</form>
<Snack name={success ? 'snackSuccess' : 'snackWarning'}
variant={success ? 'success' : 'warning'}
message={success ? 'Inscription validée.' : errors.message}
openSnack={openSnack}
onClose={this.handleClose} />
</section>
<TextField
id="outlined-bare"
className={classes.textField}
margin="normal"
variant="outlined"
inputProps={{ 'aria-label': 'bare' }}
/>
<Button variant="outlined" onClick={() => alert("Salut, tu veux faire un tuto ?")}>Ok</Button>
</div>
)
}
}
function mapStateToProps(state, ownProps) {
return {
openSnack: !_.isEmpty(ownProps.errors),
loading: !!state.user.loading,
success: state.user.NewsLetterRegistrationSuccess,
errors: state.user.errors || ownProps.errors
};
}
export default (connect(mapStateToProps, { subscribeToNewsletterRequest })(withStyles(styles)(NewsLetterRegistration)));
export default withStyles(styles)(NewsLetterRegistration)
File diff suppressed because it is too large Load Diff
+83 -125
View File
@@ -1,113 +1,83 @@
import React, { Fragment } from 'react';
import React from 'react';
import PropTypes from "prop-types";
import Router from 'next/router'
import getConfig from 'next/config'
import { withStyles } from '@material-ui/core/styles';
import Avatar from '@material-ui/core/Avatar';
import Card from '@material-ui/core/Card';
import Chip from '@material-ui/core/Chip';
import CardContent from '@material-ui/core/CardContent';
import CardHeader from '@material-ui/core/CardHeader';
import CardMedia from '@material-ui/core/CardMedia';
import Typography from '@material-ui/core/Typography';
import IconText from './../atoms/IconText';
import KeyboardArrowleftIcon from '@material-ui/icons/PlayArrowRounded';
import Link from 'next/link';
import _ from 'lodash';
const styles = theme => ({
card: {
display: 'flex',
minHeight: '21vh',
// maxHeight: '32vh',
borderRadius: '5px',
position: 'relative',
height: '50vh',
width: '100%',
cursor: 'pointer',
boxShadow: '0px 2px 4px rgba(30, 35, 39, 0.15)',
transform: 'translateY(-0px)',
transition: 'transform 0.25s, box-shadow ease-out',
'&:hover': {
boxShadow: '0px 6px 16px rgba(30, 35, 39, 0.15)',
transform: 'translateY(-5px)',
transition: 'transform 0.5s, box-shadow 2s',
'& .cardHover': {
backgroundColor: 'rgba(0,0,0,0)',
},
},
'& > div': {
padding: '0 !important',
},
[theme.breakpoints.up('md')]: {
minHeight: '15vh',
// maxHeight: '20vh',
width : '30%',
},
[theme.breakpoints.down('md')]: {
width : '40%',
},
[theme.breakpoints.down('xs')]: {
width : '100%',
},
margin: '1vh 2vh 1vh 2vh',
[theme.breakpoints.up('sm')]: {
margin: '2vh 0 2vh 0',
margin: '1vh 0 1vh 0',
},
borderRadius: 0
},
detailsContainer: {
details_container: {
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-start',
padding: theme.spacing(2),
width: '75%',
// minHeight: '200px',
alignItems: 'center',
padding: '10vh 0 0 0',
},
jobTitle: {
fontSize: '1.2em',
fontWeight: 'bold',
color: theme.palette.offerlistitem.title,
},
companyTitle: {
fontSize: '1.2em',
fontWeight: '300',
color: theme.palette.offerlistitem.title,
company_title: {
fontSize: '1em',
fontWeight: 'normal',
textTransform: 'uppercase',
},
content: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
flexWrap: 'wrap',
width: '100%',
padding: 0,
},
cover: {
position: 'relative',
width: '125px',
height: '100%',
backgroundPosition: 'center',
width: '100%',
height: '50%',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
backgroundBlendMode: 'darken',
backgroundColor: 'rgba(30,35,39,0.25)',
transition: 'background-color 1s',
[theme.breakpoints.up('md')]: {
width: '35%',
},
},
iconPlay: {
fontSize: '2em',
color: theme.palette.background.grey,
logo_container: {
display: 'flex',
alignItems: 'center',
width: 100,
height: 100,
position: 'absolute',
top: 'calc(50% - 0.5em)',
left: 'calc(50% - 0.5em)',
left: '50%',
top: '50%',
transform: 'translate(-50%, -66%)',
backgroundColor: 'white',
boxShadow: '0 8px 6px -6px grey',
},
iconText: {
marginLeft: 0,
justifyContent: 'flex-start',
logo: {
width: '100%',
height: 'auto',
objectfit: 'contain',
borderRadius: 0,
},
iconTextIcon: {
color: theme.palette.offerlistitem.icon,
fontSize: '1.2em',
},
iconTextText: {
color: theme.palette.offerlistitem.text,
fontSize: '1em',
paddingLeft: theme.spacing(1),
},
chip: {
color: theme.palette.secondary.main,
backgroundColor: theme.palette.secondary.important,
}
});
@@ -116,63 +86,51 @@ class OffreRowComponent extends React.Component {
render() {
const { classes, rowData, company } = this.props;
let companyR = company
if (!!!company)
companyR = rowData.company;
else
companyR = company;
const imgUrl = (rowData.video && rowData.video.thumbnails && rowData.video.thumbnails[0] && rowData.video.thumbnails[0].sizes[4]) ? rowData.video.thumbnails[0].sizes[4].link : publicRuntimeConfig.adListDefaultUrl
const { classes, rowData } = this.props;
const imgUrl = (rowData.video.thumbnails[0] && rowData.video.thumbnails[0].sizes[4]) ? rowData.video.thumbnails[0].sizes[4].link : publicRuntimeConfig.adListDefaultUrl
const logoUrl = publicRuntimeConfig.logoRootUrl + rowData.company.logo
//rowData._embedded.company.business_name
return (
<Link href={`/Offre/${rowData.id}-${_.kebabCase(rowData.title)}`} >
<Card className={classes.card + ' cypCardOffre'} >
<CardContent className={classes.content}>
<CardMedia
className={ classes.cover + ' cardHover'}
image={imgUrl}
title={rowData.title}
>
<KeyboardArrowleftIcon className={classes.iconPlay} />
</CardMedia>
<div className={classes.detailsContainer}>
<Typography
gutterBottom
variant="headline"
variant="h6"
component="h3"
className={classes.jobTitle}>
{rowData.title}
</Typography>
<Typography
variant="headline"
variant="h6"
component="h3"
className={classes.companyTitle}>
{companyR.brand_name ? companyR.brand_name : "Non renseigné"}
</Typography>
<div>
{rowData.is_promoted && (
<Chip label="Offre pourvue" className={classes.chip} />
)}
<Card className={classes.card} onClick={() => Router.push(`/Offre?id=${rowData.id}`)}>
<CardContent className={classes.content}>
<CardMedia
className={classes.cover}
image={imgUrl}
title={rowData.title}
/>
{!rowData.is_promoted && (
<Fragment>
<IconText classes={{ root: classes.iconText, icon: classes.iconTextIcon, text: classes.iconTextText }} variant="business_center" text={rowData.extra.contract_type} />
<IconText classes={{ root: classes.iconText, icon: classes.iconTextIcon, text: classes.iconTextText }} variant="location_on" text={rowData.location.gmap_address.formatted_address} />
{rowData.beneficiaire ? <IconText classes={{ root: classes.iconText, icon: classes.iconTextIcon, text: classes.iconTextText }} variant="business" text={rowData.beneficiaire} /> : ""}
</Fragment>
)}
<div className={classes.logo_container}>
<Avatar className={classes.logo} src={logoUrl} />
</div>
</div>
</div>
</CardContent>
</Card>
</Link>
<div className={classes.details_container}>
<Typography
gutterBottom
variant="headline"
variant="h6"
component="h3"
align="center"
className={classes.company_title}>
{rowData.company.business_name}
</Typography>
<Typography
gutterBottom
variant="headline"
variant="h6"
component="h4"
align="center"
className={classes.job_title}>
{rowData.title}
</Typography>
</div>
<div>
<Chip label={rowData.extra.contract_type} className={classes.chip} />
<Chip label={rowData.location.gmap_address.address_components[0].long_name} className={classes.chip} />
</div>
</CardContent>
</Card>
);
}
}
+55 -99
View File
@@ -8,124 +8,85 @@ import CardMedia from '@material-ui/core/CardMedia';
import Typography from '@material-ui/core/Typography';
import { withStyles } from '@material-ui/core/styles';
import Snackbar from '@material-ui/core/Snackbar';
import Collapse from '@material-ui/core/Collapse';
const styles = theme => ({
Snackbar: {
zIndex: 10001,
},
cardSnack: {
maxWidth: 345,
},
media: {
height: 140,
},
askToInstallText: {
fontSize: '1.4em',
fontWeight: '600',
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
},
installApp: {
width: '100%',
},
installStepText: {
fontSize: '1.2em',
fontWeight: '500',
color: theme.palette.primary.main,
},
button: {
color: theme.palette.primary.main,
borderColor: theme.palette.primary.main,
width: '50%',
},
buttonCompris: {
width: '100%',
},
}
});
class PWAInstallSnack extends Component {
state = {
openSnack: false,
buttonDisplay: false
buttonDisplay: true
}
isAvailable = () => {
isAvailable = () =>{
console.log(this.buttonDisplay)
return this.state.buttonDisplay;
}
initInstall = () => {
this.setState({ openSnack: true })
initInstall = () =>
{
this.setState({openSnack: true})
}
getStateAndHelpers() {
return {
on: this.state.openSnack,
initInstall: this.initInstall,
on: this.state.openSnack,
initInstall: this.initInstall,
}
}
}
iOS() {
var iDevices = [
'iPad Simulator',
'iPhone Simulator',
'iPod Simulator',
'iPad',
'iPhone',
'iPod'
'iPad Simulator',
'iPhone Simulator',
'iPod Simulator',
'iPad',
'iPhone',
'iPod'
];
if (!!navigator.platform) {
while (iDevices.length) {
if (navigator.platform === iDevices.pop()) { return true; }
}
while (iDevices.length) {
if (navigator.platform === iDevices.pop()){ return true; }
}
}
return false;
}
BeforePromptInstallTrigger() {
this.setState({ buttonDisplay: true })
}
}
componentDidMount() {
window.addEventListener('beforeinstallprompt', () => {
this.BeforePromptInstallTrigger()
})
if (!!window.deferredPrompt)
this.setState({ buttonDisplay: true });
if (typeof window !== 'undefined') {
if (window !== undefined) {
// don't show if we are in App
if (window.navigator.standalone ||
window.matchMedia('(display-mode: standalone)').matches) {
this.setState({ openSnack: false, buttonDisplay: false })
window.matchMedia('(display-mode: standalone)').matches)
{
console.log('standalone')
this.setState({ openSnack: false, buttonDisplay: false })
}
// else if (window.deferredPrompt === null) {
// this.setState({ openSnack: false, buttonDisplay: false })
// }
else if (this.IsSafari()) {
this.setState({ openSnack: false, buttonDisplay: false })
else if(this.IsSafari())
{
console.log('safari')
this.setState({ openSnack: false, buttonDisplay: false })
if (this.iOS())
{
this.setState({ openSnack: false, buttonDisplay: true })}
if(this.iOS())
this.setState({ openSnack: false, buttonDisplay: true })
}
}
}
componentWillUnmount() {
window.removeEventListener('beforeinstallprompt', () => {
this.BeforePromptInstallTrigger()
})
}
//A2HS 'Add 2 Home Screen'
PromptA2HS = (event, reason) => {
this.setState({ openSnack: false })
if (typeof window !== 'undefined') {
console.log('prompted')
if (window !== undefined) {
window.promptInstall();
}
}
@@ -144,40 +105,38 @@ class PWAInstallSnack extends Component {
const { classes } = this.props;
var safariSnack = (<Card className={classes.cardSnack}>
<CardActionArea>
<CardMedia
className={classes.media}
image="/static/images/help/addToHomeFull.png"
title="homeScreen"
/>
<CardContent>
<Typography gutterBottom component="h2">
Suivez les instructions ci -dessous :
<Typography gutterBottom variant="h5" component="h2">
-> les PWA doivent encore s'installer manuellement sous IOS
</Typography>
<Typography gutterBottom align="center" component="h2" className={ classes.installStepText }>
Etape 1 :
</Typography>
<img alt="installer-pwa" src='/static/images/help/safari-actions.png' className={classes.installApp} />
<Typography gutterBottom align="center" component="h2" className={ classes.installStepText }>
Etape 2 :
</Typography>
<img alt="installer-pwa" src='/static/images/help/safari-install-app.png' className={classes.installApp} />
</CardContent>
<CardActions>
<Button name="compris" className={classes.buttonCompris} color="primary" onClick={this.handleClose}>
j'ai compris
<Button name="compris" size="small" color="secondary" onClick={this.handleClose}>
j'ai compris
</Button>
</CardActions>
</CardActions>
</CardActionArea>
</Card>);
var usualSnack = (<Card className={classes.cardSnack}>
<CardActionArea>
<CardContent>
<Typography gutterBottom component="h2" className={ classes.askToInstallText }>
<Typography gutterBottom variant="h5" component="h2">
Voulez-vous installer notre application ?
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button className={classes.button} color="primary" name='oui' size="small" onClick={this.PromptA2HS}>
<Button name='oui' size="small" color="secondary" onClick={this.PromptA2HS}>
oui
</Button>
<Button className={classes.button} color="primary" name='non' size="small" onClick={this.handleClose}>
<Button name='non' size="small" color="secondary" onClick={this.handleClose}>
non
</Button>
</CardActions>
@@ -185,9 +144,8 @@ class PWAInstallSnack extends Component {
return <Fragment>
return <Fragment>
<Snackbar
className={ classes.Snackbar }
anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
open={this.state.openSnack}
onClose={this.handleClose}
@@ -196,11 +154,9 @@ class PWAInstallSnack extends Component {
}}>
{this.IsSafari() ? safariSnack : usualSnack}
</Snackbar>
<Collapse in={this.state.buttonDisplay}>
{this.state.buttonDisplay && this.props.children(this.getStateAndHelpers())}
</Collapse>
</Fragment>
{this.state.buttonDisplay && this.props.children(this.getStateAndHelpers())}
</Fragment>
}
}
+34 -246
View File
@@ -4,10 +4,10 @@ import dynamic from 'next/dynamic'
import Button from '@material-ui/core/Button';
import { withStyles } from '@material-ui/core/styles'
import axios from 'axios'
import CircularProgress from '@material-ui/core/CircularProgress';
import setAuthorizationHeader from "../../data/setAuthorizationHeader";
import 'videojs/dist/video-js.css';
import 'videojs-record/dist/css/videojs.record.css';
import ArrowRight from '@material-ui/icons/ArrowRight';
dynamic(() => import('webrtc-adapter'), {
ssr: false
@@ -16,208 +16,41 @@ const RTCRecorder = dynamic(() => import('RecordRTC'), {
ssr: false
})
const videoJsOptions = {
controls: true,
width: '550',
languages: {
fr: {
Replay: 'Jouer'
}
},
autoplay:true,
preload:"auto",
playsinline : false,
//videoEngine: 'webm-wasm',
//liveui : true,
fluid: true,
nativeControlsForTouch:false,
controlBar: {
// hide fullscreen and volume controls
fullscreenToggle: false,
volumePanel: false,
deviceButton: false,
recordIndicator:true,
recordToggle: false,
PictureInPictureToggle:false,
PlayToggle:false
},
poster: '/statique/images/webrtc/module-video-talents-tube.svg',
plugins: {
/*
// wavesurfer section is only needed when recording audio-only
wavesurfer: {
src: 'live',
waveColor: '#36393b',
progressColor: 'black',
debug: true,
cursorWidth: 1,
msDisplayMax: 20,
hideScrollbar: true
},
*/
record: {
audio: true,
video: true,
maxLength: 600,
//debug: true
}
}
};
const styles = theme => ({
primary: {
color: theme.palette.primary.main,
},
root: {
position: 'relative',
textAlign: 'center',
paddingTop: theme.spacing(10),
justifyContent: 'center',
const styles = theme => ({
root: {
margin: theme.spacing.unit,
maxWidth: '400px', [theme.breakpoints.down('md')]: {
maxWidth: `${100 - (theme.spacing.unit)}vw`
},
button: {
color: '#FFFFFF',
padding: '9.6px 16px',
borderColor: '#25D89A',
border: '2px solid',
margin:'15px 8px 25px 8px',
textTransform: 'inherit',
backgroundColor:'#25D89A',
},
buttonRelancer:{
color: '#1E2327',
borderColor: '#1E2327',
border: '2px solid',
margin: '15px 8px 25px 8px',
padding: '9.6px 16px',
textTransform: 'inherit',
color: '#1E2327',
borderColor: '#1E2327',
margin: theme.spacing.unit,
alignSelf: 'flex-end'
},
buttonArret: {
color: '#FFFFFF',
borderColor: '#FF5A5F',
border: '2px solid',
padding: '9.6px 16px',
margin:'15px 8px 25px 8px',
textTransform: 'inherit',
backgroundColor:'#FF5A5F',
},
buttonLire: {
color: '#FFFFFF',
padding: '9.6px 16px',
margin:'15px 8px 25px 8px',
textTransform: 'inherit',
backgroundColor:'#1689FB',
},
conteneurVideo:{
width:'550px!important'
},
sendContainer: {
left: '-40px'
},
})
// const styles = theme => ({
// root: {
// margin: theme.spacing(1),
// maxWidth: '400px', [theme.breakpoints.down('md')]: {
// maxWidth: `${100 - (theme.spacing(1))}vw`
// },
// sendContainer: {
// textAlign: 'center'
// },
// bouton: {
// textTransform: 'inherit',
// marginLeft: theme.spacing(1),
// marginRight: theme.spacing(1),
// padding: theme.spacing(1.2, 2),
// color: theme.palette.secondary.main,
// backgroundColor: theme.palette.primary.important,
// },
// conteneurVideo:{
// width:'550px!important'
// }
// }
// })
}
})
class Recorder extends Component {
state={
canSend:false,
isActiveLancer:true,
isActiveArreter:false,
isActiveLancerReplay:false,
lancerText:"Démarrer lenregistrement",
lancerStyleRelance : 0,
}
handleLancer = (replay)=>{
this.setState({
isActiveLancer: !this.state.isActiveLancer,
isActiveArreter: !this.state.isActiveArreter,
lancerText : "Refaire une vidéo",
})
replay==1 ? this.setState({isActiveLancerReplay: 1}) : this.setState({isActiveLancerReplay: 0})
this.setState({lancerStyleRelance: 1})
}
async componentDidMount() {
var record = (await import('videojs-record')).default
// instantiate Video.js
this.player = videojs(this.videoNode, videoJsOptions, () => {
this.player = videojs(this.videoNode, this.props, () => {
// print version information at startup
var version_info = 'Using video.js ' + videojs.VERSION +
' with videojs-record ' + videojs.getPluginVersion('record') +
' and recordrtc ' + RTCRecorder.VERSION;
videojs.log(version_info);
});
var vid= this.player;
this.player.bigPlayButton.hide();
// When you pass text in options it just creates a control text,
// which is displayed as tooltip when hovered on
// this button viz the span in you div,
var myButton = this.player.controlBar.addChild("button");
// There are many functions available for button component
// like below mentioned in this docs
// https://docs.videojs.com/button.
// You can set attributes and clasess as well.
// Getting html DOM
var myButtonDom = myButton.el();
//var myButtonDom2 = myButton2.el();
// Since now you have the html dom element
// you can add click events
// Now I am setting the text as you needed.
// myButtonDom.innerHTML = "Youi";
myButtonDom.onclick = function(){
//alert("Redirecting");
vid.pause();
}
// device is ready
this.player.on('deviceReady', () => {
console.info('device is ready!');
this.player.record().start();
this.setState({canSend:false});
console.log('device is ready!');
});
// user clicked the record button and started recording
this.player.on('startRecord', () => {
console.log('started recording!');
this.setState({canSend:false});
});
// user completed recording and stream is available
@@ -225,22 +58,19 @@ myButtonDom.onclick = function(){
// recordedData is a blob object containing the recorded data that
// can be downloaded by the user, stored on server etc.
console.log('finished recording: ', this.player.recordedData);
this.setState({canSend:true});
});
// error handling
this.player.on('error', (element, error) => {
console.warn(error);
this.setState({canSend:false});
});
this.player.on('deviceError', () => {
console.error('device error:', this.player.deviceErrorCode);
this.setState({canSend:false});
});
}
//destroy player on unmount
// destroy player on unmount
componentWillUnmount() {
if (this.player) {
this.player.dispose();
@@ -248,81 +78,39 @@ myButtonDom.onclick = function(){
}
sendBlob = () => {
// console.log('accessing recording: ', this.player.recordedData)
console.log('accessing recording: ', this.player.recordedData)
var formData = new FormData();
formData.append('upload', this.player.recordedData, "myupload");
// formData.append('user', 7);//TODO: taking from auth
this.props.uploader(formData);
console.log("REDIRECTION OU PAS");
console.log(this.props.retour);
if(this.props.retour=="home"){
window.location.replace("/");
}
}
setAuthorizationHeader('eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE1NTk4OTE4ODIsImV4cCI6MTU1OTg5NTQ4Miwicm9sZXMiOlsiUk9MRV9UQUxFTlQiLCJST0xFX1VTRVIiXSwidXNlcm5hbWUiOiJ0aG9tYXMuYmVycm9kQGUtZGVjbGljLmNvbSJ9.dnXiifet5SIyZf1zOBnu6RvVqA6k-aT16O_YNy6ZAhRZUuQtqP21enNkug0KxLEFMy91gcj0gkGuETqMwcHBL_xkx7rJvb2dLoOo0yduZxJLzngWKroCZE152t-V5Edn2Gje3CHMGqTZLwjBowEgUTpgfyTE9IaJn-q2pizukWBzjmfmdz5mYFgoIQrsjThkPxRH8cNOTit0bj6SebjsCCsPb_jdM6rek03qtwELz2ABJaHJU1FiGGTLYtcF3k32AGlRwa5P9etKwQUrz0AL5q3lroKgbtwhxY3cKyRKAo-o68s3v12_T6R86WqEegOx6TyBb06GJhTcP1MIGBMMgNIm5GxSi0U0RvRDmLuFtsuZv5wBUZqkpth8Z_dK5H003k67XjLrYC4TnMhQXxUGV6Eji3lkCY5fOWbQjwXRO9R_rPCNSiPEZj0o_-ach0a4Y5nLhzVlnb3J0plpb4lwpN3D9t9FNfizKQ5VX9eLoozrzkI-apIbV-Z0is8i6j4yt7R24PR9dyreQXZ3-e_tEwu5UTKi-zYAaHaHrRgCSjWg4d6ozuyXQmzi64d1-Fnx6IkU_KtXtUYRVsZhQUvJpri2x1szLLM-Hqdsh2Ljuu5qDdJrHRKeG1gZeKWPfvZweZ3SWrfvlNZHKNWX-2pmEvz9sJdpsAO-NnmTEUVrpzY')
recordPlayer = () => {
// console.log('accessing recording: ', this.player.recordedData)
if (this.player) {
//this.player.recorder.start()
this.player.ready();
this.player.record().getDevice();
this.handleLancer(0);
}
}
axios.post("http://localhost/app_dev.php/api/media",
formData,
{
headers: {
'Content-Type': `multipart/form-data;`
},
withCredentials: true
})
.then(res => console.log(res)).catch(err => console.log(err))
playPlayerAuto = () => {
// console.log('accessing recording: ', this.player.recordedData)
if (this.player) {
//this.player.recorder.start()
this.player.autoplay('play');
}
console.log('end send Blob')
}
pausePlayerAuto = () => {
// console.log('accessing recording: ', this.player.recordedData)
if (this.player) {
//this.player.recorder.start()
this.player.autoplay('pause');
}
}
arretPlayer = () => {
// console.log('accessing recording: ', this.player.recordedData)
if (this.player) {
this.player.record().stop();
this.handleLancer(1);
}
}
render() {
const { classes, titreBouton } = this.props;
let titreButtonLabel= "Choisir cette vidéo";
if (titreBouton) {
titreButtonLabel = titreBouton;
console.log("titre");
console.log(titreButtonLabel);
}
const { classes } = this.props;
return (
<div className={classes.conteneurVideo}>
<div>
<div data-vjs-player>
<video id="myVideo" width='550' ref={node => this.videoNode = node} className="video-js vjs-default-skin" playsInline></video>
<video id="myVideo" ref={node => this.videoNode = node} className="video-js vjs-default-skin" playsInline></video>
</div>
<div className={classes.sendContainer}>
{this.state.isActiveLancer ? <Button className={this.state.lancerStyleRelance==1 ? classes.buttonRelancer: classes.button} onClick={this.recordPlayer}>{this.state.lancerText}</Button> : null }
{this.state.isActiveArreter ?<Button className={classes.buttonArret} onClick={this.arretPlayer}>Arrêter l'enregistrement</Button> : null }
{/* {this.state.isActiveLancerReplay ?<Button cyp="ButtonApply" variant="contained" className={classes.buttonLire} onClick={this.playPlayerAuto}><ArrowRight className={ classes.InputKeyboardArrowRightIcon }/>Relire</Button>: null } */}
{ this.state.canSend && <Button type="submit" className={classes.button}
<div>
<Button type="submit" variant="outlined" color="secondary"
className={classes.button}
onClick={this.sendBlob}>
{titreButtonLabel}
</Button>}
</div>
<div id="controleNav">
Send
</Button>
</div>
</div>
);
+95 -267
View File
@@ -1,29 +1,21 @@
import React, { Fragment } from 'react';
import clsx from 'clsx';
import React, {Fragment} from 'react';
import { connect } from "react-redux";
import Validator from "validator";
import { TextField, FormControlLabel, Checkbox, Button, Typography, Link } from '@material-ui/core';
import {FormLabel, FormHelperText,InputLabel, Input,TextField, FormGroup, FormControlLabel, Checkbox, Button, Typography, Link } from '@material-ui/core';
import Visibility from '@material-ui/icons/Visibility';
import VisibilityOff from '@material-ui/icons/VisibilityOff';
import IconButton from '@material-ui/core/IconButton';
import InputAdornment from '@material-ui/core/InputAdornment';
import FormControl from '@material-ui/core/FormControl';
import { withStyles } from '@material-ui/core/styles';
import { registerUserRequest, subscribeToNewsletterRequest } from "../../actions/user"
import SocialButtonsAuth from '../atoms/SocialButtonsAuth';
import Snack from '../atoms/snack'
const styles = theme => ({
container: {
display: 'flex',
flexDirection: 'column',
height: '100%',
paddingTop: theme.spacing(4),
[theme.breakpoints.up('sm')]: {
padding: '5vw 10vw',
},
[theme.breakpoints.up('md')]: {
padding: '5vw 25vw',
},
},
textField: {
width: '100%'
@@ -32,107 +24,13 @@ const styles = theme => ({
display: 'flex',
flexDirection: 'column',
},
connexionRecruteur:{
textAlign : "center",
marginTop:"40px",
backgroundColor:"#1E2327",
padding:"30px 0",
width:"100%",
color:"#fff",
fontSize: '1em',
fontWeight: '300',
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
input50: {
width: '50%',
},
checkboxError:{
color:'red'
}
},
enSavoirPlus:{
textAlign : "center",
textDecoration :"none",
color:"#fff",
fontSize: '1em',
fontWeight: '600',
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
},
formText: {
padding: theme.spacing(0, 2),
paddingTop: theme.spacing(3),
fontSize: '0.9em',
fontWeight: '300',
},
formLink: {
paddingLeft: theme.spacing(1),
fontWeight: '500',
color: theme.palette.primary.dark,
},
checkbox: {
display: 'flex',
alignItems: 'center',
'& .MuiFormControlLabel-label': {
fontSize: '0.9em',
fontWeight: '500',
color: theme.palette.primary.dark,
}
},
checkboxError: {
'& .MuiFormControlLabel-label': {
color: 'red'
}
},
conditionalText: {
display: 'flex',
flexDirection: 'row',
color: theme.palette.primary.conditional,
textTransform: 'uppercase',
'&:before': {
content: '""',
flex: '1 1',
borderBottom: '1px solid',
borderColor: theme.palette.primary.conditional,
marginRight: '10px',
marginTop: 'auto',
marginBottom: 'auto',
},
'&:after': {
content: '""',
flex: '1 1',
borderBottom: '1px solid',
borderColor: theme.palette.primary.conditional,
marginLeft: '10px',
marginTop: 'auto',
marginBottom: 'auto',
},
},
button: {
textTransform: 'inherit',
marginLeft: theme.spacing(10),
marginRight: theme.spacing(10),
marginTop: theme.spacing(4),
marginBottom: theme.spacing(2),
padding: theme.spacing(1.2, 1),
borderRadius: '3px',
color: theme.palette.secondary.main,
backgroundColor: theme.palette.primary.important,
[theme.breakpoints.up('sm')]: {
margin: 'auto',
},
},
buttonImportant: {
marginTop: theme.spacing(6),
marginBottom: theme.spacing(2),
},
titre: {
fontWeight: 600,
fontSize: "1.875em",
marginBottom:"20px",
fontFamily: "Roboto",
},
cgu: {
fontFamily: "Roboto",
fontSize: "1em",
fontWeight: "300",
},
});
class Register extends React.Component {
@@ -140,25 +38,14 @@ class Register extends React.Component {
data: {
firstname: '',
lastname: '',
phone: '',
email: '',
password: '',
checkNewsletter: false,
checkCGU: false,
adId : ''
},
errors: {
email:null,
password:null,
firstname:null,
phone:null,
lastname:null,
phone:null,
checkCGU:null
},
errors: {},
loading: false,
showPassword: false,
passwordValid : false
showPassword:false
}
validate = data => {
@@ -168,29 +55,21 @@ class Register extends React.Component {
if (!!!data.firstname) errors.firstname = "Requis";
if (!!!data.lastname) errors.lastname = "Requis";
if (!data.checkCGU) errors.checkCGU = "Requis";
if(data.password.length <8){
errors.password = "Too short";
}
return errors;
};
componentDidMount() {
this.setState({
data: {...this.state.data, adId: localStorage.getItem('adId')},
})
}
onRegister = e => {
e.preventDefault();
let errors = this.validate(this.state.data);
const errors = this.validate(this.state.data);
console.log('onSubmit')
console.log(errors)
this.setState({ errors: errors });
// console.log('adId')
// console.log(this.state.data)
if (Object.keys(errors).length === 0) {
console.log(this.props.registerUserRequest(this.state.data))
if (Object.keys(errors).length === 0) {
this.setState({ loading: true });
this.props.registerUserRequest(this.state.data)
if (this.state.data.checkNewsletter)
this.props.subscribeToNewsletterRequest({ email: this.state.data.email })
@@ -198,20 +77,18 @@ class Register extends React.Component {
};
UNSAFE_componentWillReceiveProps(nextProps) {
componentWillReceiveProps(nextProps) {
this.setState({
errors: nextProps.errors,
loading: nextProps.loading
})
}
onChange = e => {
onChange = e =>
this.setState({
data: { ...this.state.data, [e.target.name]: e.target.value }
});
}
handleCheckBoxChange = name => event => {
this.setState({ data: { ...this.state.data, [name]: event.target.checked } });
this.setState({data:{ ...this.state.data, [name]: event.target.checked }});
};
handleChangePasswordVisibility = prop => event => {
@@ -223,59 +100,40 @@ class Register extends React.Component {
};
render() {
const { classes, erreurs } = this.props;
const { classes } = this.props;
const { data, errors } = this.state;
console.log('render errors');
console.log(errors);
console.log(this.state);
return (
<div className={classes.container}>
<form className={classes.form}>
<Typography
className={classes.titre}
align="left"
>
Inscription
</Typography>
<TextField
value={data.firstname}
onChange={this.onChange}
id="prenom"
name="firstname"
label="Prénom"
margin="normal"
variant="outlined"
required
error={!!errors.firstname}
helperText={!!errors.firstname && "Veuillez saisir votre prénom."}
/>
<TextField
className={classes.champ}
value={data.lastname}
onChange={this.onChange}
id="nom"
name="lastname"
label="Nom"
margin="normal"
variant="outlined"
required
error={!!errors.lastname}
helperText={!!errors.lastname && "Veuillez saisir votre nom."}
/>
<TextField
className={classes.champ}
value={data.phone}
onChange={this.onChange}
id="telephone"
name="phone"
label="Téléphone"
margin="normal"
variant="outlined"
/>
<FormGroup row>
<TextField
value={data.firstname}
className={classes.input50}
onChange={this.onChange}
id="prenom"
name="firstname"
label="Prénom"
margin="normal"
required
error={!!errors.firstname}
/>
<TextField
value={data.lastname}
className={classes.input50}
onChange={this.onChange}
id="nom"
name="lastname"
label="Nom"
margin="normal"
required
error={!!errors.lastname}
/>
</FormGroup>
<TextField
value={data.email}
@@ -285,105 +143,82 @@ class Register extends React.Component {
label="Email"
margin="normal"
type="email"
variant="outlined"
required
error={!!errors.email || !!erreurs}
helperText={!!errors.email ? "Saisissez une adresse e-mail valide." : !!erreurs && erreurs}
error={!!errors.email}
autoComplete="username email"
/>
<TextField
className={clsx(classes.margin, classes.textField)}
label="Mot de passe"
name="password"
id="adornment-password"
variant="outlined"
margin="normal"
type={this.state.showPassword ? 'text' : 'password'}
value={this.state.password}
onChange={this.onChange}
error={!!errors.password}
helperText={!!errors.password && "Votre mot de passe doit contenir au minimum 8 caractères."}
InputProps={{
endAdornment: (
<FormControl>
<InputLabel htmlFor="adornment-password">Password *</InputLabel>
<Input
name="password"
id="adornment-password"
type={this.state.showPassword ? 'text' : 'password'}
value={this.state.password}
onChange={this.onChange}
endAdornment={
<InputAdornment position="end">
<IconButton
edge="end"
aria-label="Toggle password visibility"
onClick={this.handleClickShowPassword}
>
<IconButton aria-label="Toggle password visibility" onClick={this.handleClickShowPassword}>
{this.state.showPassword ? <Visibility /> : <VisibilityOff />}
</IconButton>
</InputAdornment>
),
}}
/>
}
autoComplete="current-password"
error={!!errors.password}
/>
</FormControl>
<FormControlLabel
control={
<Checkbox
id="cypCheckboxNewsletter"
value={data.checkNewsletter}
<Checkbox value={data.checkNewsletter}
onChange={this.handleCheckBoxChange('checkNewsletter')}
/>
}
className={classes.checkbox}
label="Je souhaite recevoir la newsletter de Talents Tube"
/>
<FormControlLabel
name="checkCGU"
className={!!errors.checkCGU ? classes.checkbox + ' ' + classes.checkboxError : classes.checkbox}
className={!!errors.checkCGU&&classes.checkboxError}
control={
<Checkbox
id="cypCheckboxRegister"
<Checkbox
error={!!errors.checkCGU }
value={data.checkCGU}
onChange={this.handleCheckBoxChange('checkCGU')} required
onChange={this.handleCheckBoxChange('checkCGU')}
/>
}
label="Je déclare avoir pris connaissance et accepte les termes et les CGU *"
label="Je déclare avoir pris connaissance et accepte les termes et les CGU*"
required
/>
<Link href={`/Cgu`} className={classes.cgu}>Lire les CGU</Link>
<Button type="submit" variant="contained" className={classes.button + ' ' + classes.buttonImportant + ' cypButtonRegister'} onClick={this.onRegister}>
<Button type="submit" variant="outlined" color="primary" onClick={this.onRegister}>
S'inscrire
</Button>
{/* <Typography
paragraph={true}
align="center"
className={classes.conditionalText}
>Ou</Typography> */}
</form>
{/* <SocialButtonsAuth linkedInAuth={this.props.linkedInAuth} facebookAuth={this.props.facebookAuth} /> */}
<div classes={classes.form}>
<Typography
paragraph={true}
align="center"
className={classes.formText}
>Ou</Typography>
</form>
<Button variant="outlined" color="primary" onClick={this.props.linkedInAuth}>
Connexion avec Linkedin
</Button>
<Button variant="outlined" color="primary" onClick={this.props.facebookAuth}>
Connexion avec Facebook
</Button>
<div className={classes.form}>
<Typography
paragraph={true}
align="center"
>Je possède un compte Talents Tube ?
<Link href={"/Login"} >
<span className={classes.formLink}>
Se connecter
</span>
<Link href={"/Login"} className={classes.link}>
Se connecter
</Link>
</Typography>
</div>
<div className={classes.connexionRecruteur}>
Vous êtes recruteur ? <a className={classes.enSavoirPlus} href='https://recruteur.talentstube.com'><span >En savoir plus</span></a>
</div>
<Snack name= 'snackWarning'
variant= 'warning'
message={errors.message}
/>
</div>
</div>
</div>
);
}
}
@@ -391,14 +226,7 @@ class Register extends React.Component {
function mapStateToProps(state) {
return {
loading: !!state.user.loading,
errors: !!state.user.errors ?state.user.errors: {
phone:null,
email:null,
password:null,
firstname:null,
lastname:null,
checkCGU:null
}
errors: state.user.errors
};
}
+54 -134
View File
@@ -1,13 +1,9 @@
import Link from 'next/link';
import React, { Component } from 'react'
import { withStyles } from '@material-ui/core/styles';
import Plyr from 'react-plyr';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import withWidth, { isWidthUp } from '@material-ui/core/withWidth'
import VideoVimeo from '../atoms/VideoVimeo'
const styles = theme => ({
root: {
@@ -24,100 +20,21 @@ const styles = theme => ({
video: {
display: 'flex',
flexDirection: 'column',
position: 'relative',
'& .plyr__video-embed': {
[theme.breakpoints.up('sm')]: {
height: '40vh',
maxHeight: '40vh',
},
[theme.breakpoints.down('sm')]: {
height: '60vh',
},
},
'& .plyr__video-wrapper.plyr__video-embed': {
[theme.breakpoints.up('xs')]: {
width: '240vw',
transform: 'translateX(-55vw)',
paddingBottom: '50% !important',
},
[theme.breakpoints.up('sm')]: {
width: 'auto',
transform: 'inherit',
},
},
'& .plyr__controls': {
background: 'none'
},
},
videoVimeo: {
zIndex: '888',
height: '65vh',
paddingBottom: '0%',
overflow: 'hidden',
'& iframe': {
position: 'absolute',
top: 0,
left: 'calc(50% - 125vw)',
width: '250vw',
height: '120vw',
},
[theme.breakpoints.up('md')]: {
height: '48vw',
paddingBottom: '0',
'& iframe': {
position: 'absolute',
left: 'calc(50% - 100vw)',
width: '200vw',
height: '130%',
},
},
[theme.breakpoints.up('lg')]: {
height: '48vw',
},
},
text: {
zIndex: '999',
display: 'flex',
flexDirection: 'column',
alignItems: 'flex-start',
position: 'absolute',
bottom: '17vh',
left: '3vh',
},
textCompany: {
color: theme.palette.secondary.main,
backgroundColor: 'rgba(30,35,39,0.9)',
padding: theme.spacing(0.8, 2),
marginBottom: 0,
fontWeight: 'bold',
fontSize: '1em',
},
textJob: {
color: theme.palette.secondary.main,
backgroundColor: 'rgba(30,35,39,0.5)',
padding: theme.spacing(0.4, 2),
marginBottom: 0,
fontWeight: 'lighter',
fontSize: '0.9em',
},
button: {
position: 'absolute',
bottom: '5vh',
left: '3vh',
padding: theme.spacing(1, 4),
textTransform: 'inherit',
zIndex: '999',
},
plyr: {
'.plyr--video .plyr__controls': {
background: null
}
}
});
const videoList = [
{ vimeoId: '350927569', title: 'Les Vergers de Châteaubourg', adTitle: 'Conducteurs de ligne (H/F)', link: '/Offre/73-Les-Vergers-de-Châteaubourg-chateaubourg' },
{ vimeoId: '350927551', title: 'Grand Ouest Étiquettes', adTitle: 'Conducteurs de machine dimpression', link: '/Offre/79-Grand-Ouest-Étiquettes-Saint-Brieuc' },
{ vimeoId: '350927537', title: 'Fym Action', adTitle: 'Promoteur des ventes en alimentaire (H/F)', link: '/Offre/81-Fym-Action-Caudan' }
]
const videoList = [{ vimeoId: '228345901', title: 'Eurofins', adTitle: 'CDI gestion', link: '/offre?id=22' },
{ vimeoId: '230731700', title: 'MULTIPLAST', adTitle: 'CDI example', link: '/offre?id=24' },
{ vimeoId: '232953887', title: 'Actual', adTitle: 'Chef général', link: '/offre?id=26' }]
class ShortVideoHooker extends Component {
constructor(props) {
@@ -137,7 +54,7 @@ class ShortVideoHooker extends Component {
componentDidMount() {
this.timer = setInterval(this.tick.bind(this), 2000);
this.timer = setInterval(this.tick.bind(this), 500);
}
componentWillUnmount() {
@@ -145,7 +62,7 @@ class ShortVideoHooker extends Component {
}
tick() {
// console.log(this.state)
if (new Date() - this.state.startDate >= 8000) {
if (this.state.i == 2)
@@ -153,13 +70,13 @@ class ShortVideoHooker extends Component {
else
this.setState({ i: ++this.state.i, startDate: Date.now() })
//Update Plyr
// if (this.plyrRef) {
// this.plyrRef.hideControls = true;
// this.plyrRef.displayDuration = false;
// this.plyrRef.updateVideoSource(videoList[this.state.i].vimeoId, 'vimeo')
// this.plyrRef.hideControls = true;
// this.plyrRef.displayDuration = false;
// }
if (this.plyrRef) {
this.plyrRef.hideControls = true;
this.plyrRef.displayDuration = false;
this.plyrRef.updateVideoSource(videoList[this.state.i].vimeoId, 'vimeo')
this.plyrRef.hideControls = true;
this.plyrRef.displayDuration = false;
}
}
}
@@ -167,42 +84,45 @@ class ShortVideoHooker extends Component {
render() {
let { classes } = this.props;
let videoId = videoList[0].vimeoId;
// console.log(videoId)
return (
<div className={classes.video}>
{/* <VideoVimeo classesOverride={ classes.videoVimeo } videoId={videoId}
options={`?byline=0&title=0&background=1&autoplay=1&mute=1`} />
<section className={classes.text}>
<Typography gutterBottom
variant="headline"
variant="h6"
component="h4"
align="center"
className={classes.textCompany}>
{videoList[this.state.i].title}
</Typography>
{/* config at : https://github.com/xDae/react-plyr */}
<Plyr
//autoplay
type="vimeo" // or "vimeo"
videoId={videoId}
//displayDuration={false}
hideControls={true}
clickToPlay={false}
fullscreen={{ enabled: false, fallback: true, iosNative: false }}
disableContextMenu={true}
controls={null}
ref={this.setPlyrRef}
className={classes.plyr}
/>
<Typography gutterBottom
variant="headline"
variant="h6"
component="h4"
align="center"
className={classes.text}>
{videoList[this.state.i].title}
</Typography>
<Typography gutterBottom
variant="headline"
variant="h6"
component="h4"
align="center"
className={classes.textJob}>
{videoList[this.state.i].adTitle}
</Typography>
</section>
<Link href={videoList[this.state.i].link}>
<Button
name="Offre"
className={classes.button}
variant="outlined"
color="secondary"
>
Voir l'offre
<Typography gutterBottom
variant="headline"
variant="h6"
component="h4"
align="center"
className={classes.text}>
{videoList[this.state.i].adTitle}
</Typography>
<Button variant="outlined">
Voir l'offre
</Button>
</Link> */}
</div>
)
}
}
export default withStyles(styles)(withWidth()(ShortVideoHooker))
export default withStyles(styles)(ShortVideoHooker);
-123
View File
@@ -1,123 +0,0 @@
import React from 'react';
import Link from 'next/link';
import clsx from 'clsx';
import { loadCSS } from 'fg-loadcss';
import { makeStyles } from '@material-ui/core/styles';
import { red } from '@material-ui/core/colors';
import Icon from '@material-ui/core/Icon';
import Hidden from '@material-ui/core/Hidden';
const useStyles = makeStyles(theme => ({
root: {
display: 'flex',
justifyContent: 'center',
alignItems: 'flex-end',
},
iconHover: {
margin: theme.spacing(2),
'&:hover': {
color: red[800],
},
},
icon: {
margin: theme.spacing(1.5),
padding: theme.spacing(1.5),
borderRadius: '20px',
fontSize: '1em',
textAlign: 'center',
},
FacebookIcon: {
color: theme.palette.social.facebook,
'&:hover': {
backgroundColor: theme.palette.social.facebook,
color: '#fff',
}
},
TwitterIcon: {
color: theme.palette.social.twitter,
'&:hover': {
backgroundColor: theme.palette.social.twitter,
color: '#fff',
}
},
LinkedinIcon: {
color: theme.palette.social.linkedin,
'&:hover': {
backgroundColor: theme.palette.social.linkedin,
color: '#fff',
}
},
MailIcon: {
color: theme.palette.social.mail,
'&:hover': {
backgroundColor: theme.palette.social.mail,
color: '#fff',
}
},
FacebookIconMobile: {
color: theme.palette.social.facebook,
paddingRight:'0px',
paddingLeft:'3px'
},
TwitterIconMobile: {
color: theme.palette.social.twitter,
paddingRight:'3px' ,
paddingLeft:'3px'
},
LinkedinIconMobile: {
color: theme.palette.social.linkedin,
paddingRight:'3px',
paddingLeft:'3px'
},
MailIconMobile: {
color: theme.palette.social.mail,
paddingRight:'3px' ,
paddingLeft:'3px'
},
}));
export default function SocialShare(props) {
const classes = useStyles();
React.useEffect(() => {
loadCSS(
'https://use.fontawesome.com/releases/v5.1.0/css/all.css',
document.querySelector('#font-awesome-css'),
);
}, []);
return (
<div className={classes.root}>
<Hidden smDown>
<a href={"https://www.facebook.com/sharer/sharer.php?u=" + encodeURIComponent(props.url)} target="_blank">
<Icon className={clsx(classes.icon, classes.FacebookIcon, 'fab fa-facebook-f')} />
</a>
<a href={"http://twitter.com/share?url=" + encodeURIComponent(props.url)} target="_blank">
<Icon className={clsx(classes.icon, classes.TwitterIcon, 'fab fa-twitter')} color="secondary" />
</a>
<a href={"https://www.linkedin.com/shareArticle?mini=true&url=" + encodeURIComponent(props.url + "&title=Talents Tube")} target="_blank">
<Icon className={clsx(classes.icon, classes.LinkedinIcon, 'fab fa-linkedin-in')} color="secondary" />
</a>
{/* change because of https://github.com/zeit/next.js/blob/master/errors/invalid-href-passed.md */}
<a href={"mailto:?subject=Offre d'emploi Talents Tube&body=Regardez cette offre : " + props.url} target="_blank"s>
<Icon className={clsx(classes.icon, classes.MailIcon, 'fas fa-envelope')} color="secondary" />
</a>
</Hidden>
<Hidden mdUp>
<a href={"https://www.facebook.com/sharer/sharer.php?u=" + encodeURIComponent(props.url)} target="_blank">
<Icon className={clsx(classes.icon, classes.FacebookIconMobile, 'fab fa-facebook-f')} />
</a>
<a href={"http://twitter.com/share?url=" + encodeURIComponent(props.url)} target="_blank">
<Icon className={clsx(classes.icon, classes.TwitterIconMobile, 'fab fa-twitter')} color="secondary" />
</a>
<a href={"https://www.linkedin.com/shareArticle?mini=true&url=" + encodeURIComponent(props.url + "&title=Talents Tube")} target="_blank">
<Icon className={clsx(classes.icon, classes.LinkedinIconMobile, 'fab fa-linkedin-in')} color="secondary" />
</a>
{/* change because of https://github.com/zeit/next.js/blob/master/errors/invalid-href-passed.md */}
<a href={"mailto:?subject=Offre d'emploi Talents Tube&body=Regardez cette offre : " + props.url} target="_blank"s>
<Icon className={clsx(classes.icon, classes.MailIconMobile, 'fas fa-envelope')} color="secondary" />
</a>
</Hidden>
</div>
);
}
+55 -62
View File
@@ -5,80 +5,79 @@ import getConfig from 'next/config'
import { withStyles } from '@material-ui/core/styles';
import Avatar from '@material-ui/core/Avatar';
import Card from '@material-ui/core/Card';
import Chip from '@material-ui/core/Chip';
import CardContent from '@material-ui/core/CardContent';
import CardHeader from '@material-ui/core/CardHeader';
import CardMedia from '@material-ui/core/CardMedia';
import KeyboardArrowleftIcon from '@material-ui/icons/PlayArrowRounded';
import Link from 'next/link';
import _ from 'lodash';
import Typography from '@material-ui/core/Typography';
const styles = theme => ({
card: {
display: 'flex',
height: '400px',
position: 'relative',
height: '60vh',
width: '100%',
cursor: 'pointer',
transform: 'translateY(-0px)',
transition: 'transform 0.25s',
'&:hover': {
transform: 'translateY(-15px)',
transition: 'transform 0.5s, box-shadow 1.2s',
'& .cardHover': {
backgroundColor: 'rgba(0,0,0,0)',
},
[theme.breakpoints.up('md')]: {
width: '30%',
},
[theme.breakpoints.down('md')]: {
width: '40%',
},
[theme.breakpoints.down('xs')]: {
width: '100%',
},
margin: '2vh 3vh 3vh 1vh',
[theme.breakpoints.up('sm')]: {
margin: '1vh 0 1vh 0',
height: '530px',
},
[theme.breakpoints.up('md')]: {
height: '404px',
},
borderRadius: '0.2em',
},
details_container: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: '8vh 0 0 0',
},
company_title: {
fontSize: '1em',
fontWeight: 'normal',
textTransform: 'uppercase',
},
content: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
flexWrap: 'wrap',
width: '100%',
padding: 0,
},
cover: {
width: '100%',
height: '45%',
height: '50%',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
backgroundBlendMode: 'darken',
backgroundColor: 'rgba(30,35,39,0.25)',
transition: 'background-color 1s',
},
logoContainer: {
logo_container: {
display: 'flex',
alignItems: 'center',
width: 80,
height: 80,
width: 70,
height: 70,
position: 'absolute',
left: '50%',
top: '45%',
top: '50%',
transform: 'translate(-50%, -66%)',
border: 'solid 5px white',
backgroundColor: 'white',
boxShadow: '0px 6px 15px rgba(30, 35, 39, 0.10)',
borderRadius: '5px',
},
iconPlay: {
fontSize: '3em',
color: theme.palette.background.grey,
position: 'absolute',
left: 'calc(50% - 0.5em)',
top: 'calc(22.5% - 0.5em)',
boxShadow: '0 8px 6px -6px grey',
border: 'solid 5px white',
borderRadius: '0.5em',
},
logo: {
width: '100%',
height: 'auto',
objectfit: 'contain',
borderRadius: 'inherit',
},
chip: {
margin: '0 1vh 0 1vh',
@@ -91,34 +90,28 @@ const { publicRuntimeConfig } = getConfig()
class Tile extends React.Component {
render() {
const { classes, rowData, children, tileIndex } = this.props;
const imgAdUrl = (rowData.video && rowData.video.thumbnails[0] && rowData.video.thumbnails[0].sizes[4]) ? rowData.video.thumbnails[0].sizes[4].link : publicRuntimeConfig.adListDefaultUrl
const imgCompanyUrl = (rowData.presentation_video && rowData.presentation_video.thumbnails[0] && rowData.presentation_video.thumbnails[0].sizes[4]) ? rowData.presentation_video.thumbnails[0].sizes[4].link : publicRuntimeConfig.adListDefaultUrl
const imgUrl = (rowData.video) ? imgAdUrl : imgCompanyUrl
const logoName = (rowData.company) ? rowData.company.logo : rowData.logo
const logoUrl = publicRuntimeConfig.symphonyUrl + publicRuntimeConfig.cachedMediaUrl + logoName
const { classes, rowData, children } = this.props;
const router = (rowData.company) ? `/Offre/${rowData.id}-${_.kebabCase(rowData.title)}` : `/Entreprise/${rowData.id}-${_.kebabCase(rowData.brand_name)}}`
//rowData._embedded.company.brand_name
const imgUrl = (rowData.video.thumbnails[0] && rowData.video.thumbnails[0].sizes[4]) ? rowData.video.thumbnails[0].sizes[4].link : publicRuntimeConfig.adListDefaultUrl
const logoUrl = publicRuntimeConfig.logoRootUrl + rowData.company.logo
//rowData._embedded.company.business_name
return (
<Link href={router} >
<Card cyp="CardOneOffers" className={classes.card}>
<CardContent className={classes.content}>
<CardMedia
className={classes.cover + ' cardHover'}
image={imgUrl}
title={rowData.title}
/>
<KeyboardArrowleftIcon className={classes.iconPlay} />
<div className={classes.logoContainer}>
<Avatar className={classes.logo} src={logoUrl} alt={rowData.title}/>
</div>
{ children }
</CardContent>
</Card>
</Link>
<Card className={classes.card} onClick={() => Router.push(`/Offre?id=${rowData.id}`)}>
<CardContent className={classes.content}>
<CardMedia
className={classes.cover}
image={imgUrl}
title={rowData.title}
/>
<div className={classes.logo_container}>
<Avatar className={classes.logo} src={logoUrl} />
</div>
{ children }
</CardContent>
</Card>
);
}
}
@@ -126,7 +119,7 @@ class Tile extends React.Component {
Tile.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
rowData: PropTypes.object.isRequired,
rowData: PropTypes.object.isRequired
};
export default withStyles(styles, { withTheme: true })(Tile);
+27 -46
View File
@@ -3,88 +3,69 @@ import PropTypes from "prop-types";
import Router from 'next/router'
import getConfig from 'next/config'
import { withStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import Chip from '@material-ui/core/Chip';
import IconText from './../atoms/IconText';
import Typography from '@material-ui/core/Typography';
const styles = theme => ({
detailsContainer: {
details_container: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'space-between',
position: 'absolute',
top: '60%',
width: '100%',
minHeight: '35%',
padding: '8vh 0 0 0',
},
companyTitle: {
company_title: {
fontSize: '1em',
paddingLeft: theme.spacing(1),
paddingRight: theme.spacing(1),
minHeight: '8vh',
[theme.breakpoints.up('md')]: {
minHeight: 'inherit',
},
fontWeight: 'normal',
textTransform: 'uppercase',
},
chip: {
height: '27px',
padding: theme.spacing(1),
margin: '0 1vh 0 1vh',
},
rootIconText: {
margin: 0,
padding: theme.spacing(0.5, 0),
color: theme.palette.secondary.dark,
'& p ': {
color: theme.palette.secondary.text,
}
}
});
class CompanyOffre extends React.Component {
class TileCompany extends React.Component {
render() {
const { classes, tile } = this.props;
const offre = (tile.count_ads == 1) ? tile.count_ads + ' offre' : tile.count_ads + ' offres'
const nbOffre = (tile.count_ads > 0) ? offre : 'Candidature spontanée'
return (
<Fragment>
<section className={classes.detailsContainer}>
<div className={classes.details_container}>
<Typography
gutterBottom
variant="headline"
variant="h6"
component="h4"
align="center"
className={classes.company_title}>
{tile.company.business_name}
</Typography>
<Typography
gutterBottom
variant="headline"
variant="h6"
component="h3"
align="center"
className={classes.companyTitle}>
{tile.brand_name ? tile.brand_name : "-"}
className={classes.job_title}>
{tile.title}
</Typography>
{tile.addresses && tile.addresses.billing && tile.addresses.billing.city &&
<IconText classes={{ root: classes.rootIconText }} variant="location_on" text={tile.addresses.billing.city} />
}
{tile.title &&
<IconText classes={{ root: classes.rootIconText }} variant="business_center" text={tile.title} />
}
{nbOffre &&
<Chip color="primary" label={nbOffre} className={classes.chip} />
}
</section>
</div>
<div>
<Chip label={tile.extra.contract_type} className={classes.chip} />
<Chip label={tile.location.gmap_address.address_components[0].long_name} className={classes.chip} />
</div>
</Fragment>
);
}
}
CompanyOffre.propTypes = {
TileCompany.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
tile: PropTypes.object.isRequired
};
export default withStyles(styles, { withTheme: true })(CompanyOffre);
export default withStyles(styles, { withTheme: true })(TileCompany);
+28 -51
View File
@@ -1,44 +1,31 @@
import React, { Fragment } from 'react';
import PropTypes from "prop-types";
import Router from 'next/router'
import getConfig from 'next/config'
import { withStyles } from '@material-ui/core/styles';
import Chip from '@material-ui/core/Chip';
import Typography from '@material-ui/core/Typography';
import Icon from '@material-ui/core/Icon';
import IconText from './../atoms/IconText';
const styles = theme => ({
detailsContainer: {
details_container: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
position: 'absolute',
top: '44%',
width: '100%',
alignItems: 'center',
padding: '8vh 0 0 0',
},
companyTitle: {
fontSize: '1em',
fontWeight: '100',
padding: theme.spacing(0, 2),
marginTop: '4vh',
minHeight: '6vh',
[theme.breakpoints.up('md')]: {
minHeight: '3vh',
},
company_title: {
fontSize: '0.8em',
fontWeight: 'normal',
},
jobTitle: {
fontSize: '1.2em',
padding: theme.spacing(0, 2),
minHeight: '8vh',
[theme.breakpoints.up('lg')]: {
minHeight: '50px',
},
job_title: {
fontSize: '1em',
marginLeft: theme.spacing(1),
marginRight: theme.spacing(1),
},
rootIconText: {
margin: 0,
padding: theme.spacing(0.5, 2),
color: theme.palette.secondary.dark,
justifyContent: 'flex-start',
'& p ': {
color: theme.palette.secondary.text,
}
chip: {
margin: '0 1vh 0 1vh',
}
});
@@ -51,41 +38,31 @@ class TileOffre extends React.Component {
return (
<Fragment>
<section className={classes.detailsContainer} >
<section className={classes.details_container}>
<Typography
gutterBottom
variant="headline"
variant="h6"
component="h4"
align="center"
className={classes.companyTitle}>
{tile.company.brand_name && tile.company.brand_name}
className={classes.company_title}>
{tile.company.business_name}
</Typography>
<Typography
gutterBottom
variant="headline"
variant="h6"
component="h3"
align="left"
className={classes.jobTitle}>
{tile.title && tile.title}
align="center"
className={classes.job_title}>
{tile.title}
</Typography>
{/*
<IconText classes={{root: classes.rootIconText}} variant="business_center" text={tile.title} />
*/}
{tile.location && tile.location.gmap_address && tile.location.gmap_address.address_components && tile.location.gmap_address.address_components[0].long_name &&
<IconText classes={{ root: classes.rootIconText }} variant="location_on" text={tile.location.gmap_address.address_components[0].long_name} />
}
{tile.extra && tile.extra.contract_type &&
<IconText classes={{ root: classes.rootIconText }} variant="assignment" text={tile.extra.contract_type} />
}
{tile.beneficiaire &&
<IconText classes={{ root: classes.rootIconText }} variant="business" text={tile.beneficiaire} />
}
</section>
<section>
<Chip label={tile.extra.contract_type} className={classes.chip} />
<Chip label={tile.location.gmap_address.address_components[0].long_name} className={classes.chip} />
<IconText />
<Icon>add_circle</Icon>
</section>
</Fragment>
);
+2 -3
View File
@@ -1,6 +1,5 @@
import React, { lazy } from 'react';
const videojs = lazy(() => import('video.js'));
//import videojs from 'video.js'
import React from 'react';
import videojs from 'video.js'
export default class VideoPlayer extends React.Component {
componentDidMount() {
+24
View File
@@ -0,0 +1,24 @@
import Link from 'next/link'
import { withStyles } from '@material-ui/core/styles'
import BottomToolbar from '../organisms/BottomToolbar';
import { Fragment } from 'react';
const styles = theme => ({
root: {
position: 'relative',
height: '10vh'
},
});
function Footer(props) {
const { classes } = props;
return (
<Fragment>
</Fragment>
);
}
export default withStyles(styles)(Footer)
+51 -277
View File
@@ -1,68 +1,15 @@
import Griddle, { utils, plugins } from "griddle-react";
import Griddle, { utils } from "griddle-react";
import PropTypes from 'prop-types';
import React, { Component, Fragment } from 'react';
import { withStyles } from '@material-ui/core/styles';
import { Button } from '@material-ui/core';
import TextField from '@material-ui/core/TextField';
import React, { Component } from 'react';
import { connect } from "react-redux";
import OffreRow from "../organisms/OffreRow"
import GriddleCustomTable from "../organisms/GriddleCustomTableComponent";
import GriddleCustomNextButton from "../organisms/GriddleCustomNextButton"
import GriddleCustomPreviousButton from "../organisms/GriddleCustomPreviousButton"
import GriddleCustomPageDropdown from "../organisms/GriddleCustomPageDropdown"
import Loader from './loader'
import IconSearch from '@material-ui/icons/Search';
import NoResult from './../atoms/NoResult';
import _ from "lodash";
//insights
//
//https://codesandbox.io/s/pw9zy43v1m?module=%2FGrid.js
const styles = theme => ({
textField: {
textAlign: 'center',
justifyContent: 'center',
margin: 0,
'& input': {
fontWeight: '300',
color: theme.palette.primary.dark,
backgroundColor: theme.palette.background.grey,
minWidth: '75vw',
padding: 0,
margin: 0,
paddingLeft: theme.spacing(2),
[theme.breakpoints.up('md')]: {
minWidth: '85vw',
},
}
},
griddle: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
'& .griddle-pagination': {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
},
button: {
padding: theme.spacing(2, 0),
boxShadown: '0px',
backgroundColor: theme.palette.background.grey,
},
filterForm: {
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
backgroundColor: theme.palette.background.grey,
position: 'absolute',
top: 0,
left: 0,
width: '100% !important',
[theme.breakpoints.up('md')]: {
justifyContent: 'space-evenly',
},
},
})
const CustomTableBody = ({ rowIds, Row, style, className }) => (
<div style={style} className={className}>
@@ -77,189 +24,65 @@ class Grid extends Component {
success: false,
data: {},
currentPage: 1,
pageSize: 12,
pageSize: 10,
recordCount: 0,
promoted: false,
filterText: "",
// options: [],
filterText: ""
};
async componentDidMount() {
this.setState({pageSize:this.props.limit})
let data = sessionStorage.getItem(this.props.type+'_currentPage');
let current;
if(data){
current=data;
}else{
current=this.state.currentPage;
}
this.props.dataFetcher(
{
offset: ((current-1)*this.props.limit)+1,
limit: this.props.limit
offset: this.state.currentPage,
limit: this.state.pageSize
}
);
// let options = [];
// let startIndex = Math.max(this.props.currentPage - 5, 0);
// let endIndex = Math.min(startIndex + 11, this.props.maxPage);
// if (this.props.maxPage >= 11 && (endIndex - startIndex) <= 10) {
// startIndex = endIndex - 11;
// }
// for(let i = startIndex; i < endIndex ; i++){
// let selected = this.props.currentPage == i ? "current-page-selected" : "";
// options.push(<button className={selected} data-value={i} onClick={this.pageChange}>{i + 1}</button>);
// }
}
UNSAFE_componentWillReceiveProps(nextProps) {
componentWillReceiveProps(nextProps) {
this.setState({ data: nextProps.data });
this.setState({ currentPage: nextProps.currentPage });
this.setState({ recordCount: nextProps.recordCount });
this.setState({ loading: nextProps.loading });
this.setState({ limit: nextProps.limit });
const { currentPage, pageSize, filterText, promoted } = this.state;
if (nextProps.promoted != this.state.promoted) {
let data = sessionStorage.getItem(this.props.type+'_currentPage');
let current;
if(data){
current=data;
}else{
current=this.state.currentPage;
}
this.setState({ promoted: nextProps.promoted });
this.props.dataFetcher(
{
offset: ((current-1)*(this.state.pageSize+1))+1,
limit: this.state.pageSize,
keyword: filterText,
isPromoted: nextProps.promoted
}
);
}
window.scrollTo(0, 0);
}
_onNext = () => {
const { currentPage, pageSize, filterText, promoted } = this.state;
this.props.dataFetcher({ offset: currentPage * pageSize, limit: pageSize, keyword: filterText, isPromoted: promoted })
sessionStorage.setItem(this.props.type+'_currentPage', currentPage+1);
const { currentPage, pageSize, filterText } = this.state;
console.debug(`-- _onNext -- ${0} -- ${1} -- ${2} --`, currentPage, pageSize, filterText)
this.props.dataFetcher({ offset: currentPage * pageSize, limit: pageSize, keyword: filterText })
};
_onPrevious = () => {
const { currentPage, pageSize, filterText, promoted } = this.state;
this.props.dataFetcher({ offset: (currentPage - 2) * pageSize + 1, limit: pageSize, keyword: filterText, isPromoted: promoted });
sessionStorage.setItem(this.props.type+'_currentPage', currentPage-1);
const { currentPage, pageSize, filterText } = this.state;
this.props.dataFetcher({ offset: (currentPage - 2) * pageSize + 1, limit: pageSize, keyword: filterText });
};
_onGetPage = (pageNumber, page) => {
const { pageSize, filterText, promoted } = this.state;
this.props.dataFetcher({ offset: (page - 1) * pageSize + 1, limit: pageSize, keyword: filterText, isPromoted: promoted });
console.log(pageNumber);
console.log(page);
sessionStorage.setItem(this.props.type+'_currentPage', page);
console.log("On get Page");
};
_onSetPage = pageNumber => {
const { pageSize, filterText, promoted } = this.state;
this.props.dataFetcher({ offset: (pageNumber - 1) * pageSize + 1, limit: pageSize, keyword: filterText, isPromoted: promoted });
console.log("On set Page");
_onGetPage = pageNumber => {
const { pageSize, filterText } = this.state;
this.props.dataFetcher({ offset: (pageNumber - 1) * pageSize + 1, limit: pageSize, keyword: filterText });
};
_onFilter = filterText => {
sessionStorage.setItem(this.props.type+'_currentPage', 1);
this.setState({ currentPage: 1 });
const { currentPage, pageSize, promoted } = this.state;
const { currentPage, pageSize } = this.state;
this.setState({ filterText });
this.props.dataFetcher({ offset: (currentPage - 1) * pageSize + 1, limit: pageSize, keyword: filterText, isPromoted: promoted });
this.props.dataFetcher({ offset: (currentPage - 1) * pageSize + 1, limit: pageSize, keyword: filterText });
};
searchChange = e => {
this.setState({ filterText: e.target.value });
}
searchSubmit = () => {
const { currentPage, pageSize, promoted, filterText } = this.state;
sessionStorage.setItem(this.props.type+'_currentPage', 1);
this.props.dataFetcher({ offset: 1, limit: pageSize, keyword: filterText, isPromoted: promoted });
}
render() {
const { classes, placeholder } = this.props
const style = {
styles: {
TableBody: {
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'space-around'
},
Pagination: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
paddingTop: '32px',
},
NextButton: {
fontSize: '0.9em',
fontWeight: '600',
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
textTransform: 'inherit',
marginLeft: '64px',
marginRight: '64px',
marginTop: '32px',
marginBottom: '16px',
padding: '9px 16px',
borderRadius: '3px',
backgroundColor: 'transparent',
border: '1px solid #E8E8E9',
color: '#787B7D',
cursor: 'pointer',
},
PreviousButton: {
fontSize: '0.9em',
fontWeight: '600',
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
textTransform: 'inherit',
marginLeft: '64px',
marginRight: '64px',
marginTop: '32px',
marginBottom: '16px',
padding: '9px 16px',
borderRadius: '3px',
backgroundColor: 'transparent',
border: '1px solid #E8E8E9',
color: '#787B7D',
cursor: 'pointer',
},
PageDropdown: {
fontSize: '0.9em',
fontWeight: '600',
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
// display: 'none',
},
TableBody: { display: "flex", flexWrap: "wrap", justifyContent: "space-around" },
}
}
const { filterText, data, currentPage, pageSize, recordCount, loading } = this.state;
const { data, currentPage, pageSize, recordCount } = this.state;
// console.debug("-- render -- ")
// console.debug(data)
const NewLayout = ({ Table, Pagination, Filter }) => (
<div>
{/* <Filter /> */}
<Table />
<Filter />
<Pagination />
<Table />
</div>
);
@@ -280,88 +103,39 @@ class Grid extends Component {
return (
<div>
{this.props.searchable &&
<div className={classes.filterForm}>
<TextField
id="standard-search"
disabled={loading}
name="search"
value={filterText}
onChange={this.searchChange}
placeholder={placeholder}
className={classes.textField}
InputLabelProps={{
shrink: true,
}}
margin="dense"
variant="filled"
onKeyPress={(ev) => {
if (ev.key === 'Enter') {
this.searchSubmit()
}
}}
type="search"
/>
<Button onClick={this.searchSubmit}
disabled={loading}
variant="contained"
className={classes.button}>
<IconSearch />
</Button >
</div>
}
{loading ?
(<Loader />)
: !_.isEmpty(data) ? (
<Griddle
className={classes.griddle}
data={data}
pageProperties={{
currentPage,
pageSize,
recordCount,
}}
useCustomPagerComponent="true"
plugins={plugins.localPlugin}
components={{
Layout: NewLayout,
Row: this.props.CustomRowComponent,
TableContainer: GriddleCustomTable,
TableBody: CustomTableBody,
PreviousButton: GriddleCustomPreviousButton,
NextButton: GriddleCustomNextButton,
PageDropdown: GriddleCustomPageDropdown,
}}
events={{
onNext: this._onNext,
onPrevious: this._onPrevious,
onGetPage: this._onGetPage,
onFilter: this._onFilter,
onSetPage: this._onSetPage
}}
styleConfig={style}
/>
) : (<NoResult text='Aucun résultat.' />)
}
<Griddle
data={data}
pageProperties={{
currentPage,
pageSize,
recordCount
}}
components={{
Layout: NewLayout,
Row: this.props.CustomRowComponent,
TableContainer: GriddleCustomTable,
TableBody: CustomTableBody
}}
events={{
onNext: this._onNext,
onPrevious: this._onPrevious,
onGetPage: this._onGetPage,
onFilter: this._onFilter
}}
styleConfig={style}
/>
</div>
)
}
}
Grid.defaultProps = {
offset: 1,
limit: 12,
searchable: true
}
Grid.propTypes = {
dataFetcher: PropTypes.func.isRequired,
CustomRowComponent: PropTypes.any.isRequired,
data: PropTypes.any,
searchable: PropTypes.bool
data: PropTypes.any
}
export default withStyles(styles)(Grid);
export default Grid;
+28 -10
View File
@@ -1,25 +1,43 @@
import { withStyles } from '@material-ui/core/styles'
import RootContainer from '../atoms/RootContainer'
import Header from '../organisms/Header'
const styles = theme => ({
root: {
height: '100%'
},
head: {
width: '100%',
height: '64px',
background: theme.palette.secondary.main,
height: '56px',
background: 'silver',
position: 'fixed',
zIndex: '1199',
[theme.breakpoints.up('sm')]: {
height: '64px'
}
},
foot: {
height: '64px',
height: '56px',
width: '100%',
position: 'relative',
top: '64px',
top: '56px',
[theme.breakpoints.up('sm')]: {
height: '64px',
top: '64px'
},
},
content: {
top: '64px',
height: 'calc(100vh - 64px)',
top: '56px',
height: 'calc(100vh - 112px)',
[theme.breakpoints.up('sm')]: {
top: '64px',
height: 'calc(100vh - 128px)',
},
position: 'relative',
overflow: 'auto',
}
});
@@ -28,7 +46,7 @@ function Layout(props) {
const { classes } = props;
return (
<RootContainer>
<div className={classes.root}>
<div id="H" className={classes.head}>
<div className={classes.inner}>
<Header searchBar={true}/>
@@ -38,7 +56,7 @@ function Layout(props) {
{props.children}
</div>
</RootContainer>
</div>
)
}
-184
View File
@@ -1,184 +0,0 @@
import React, { Component, useEffect } from 'react'
import { withStyles } from '@material-ui/core/styles'
import Router from 'next/router';
import RootContainer from '../atoms/RootContainer'
import ButtonBase from "@material-ui/core/ButtonBase";
import ArrowLeft from '@material-ui/icons/KeyboardArrowLeft';
import Typography from '@material-ui/core/Typography';
import { Button, Hidden } from '@material-ui/core';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
const styles = theme => ({
inner: {
height: '100%',
position: 'relative',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.04), 0 1px 10px 0 rgba(0, 0, 0, 0.04), 0 3px 5px -1px rgba(0, 0, 0, 0.04)',
backgroundColor: theme.palette.secondary.main,
},
head: {
zIndex: '999',
width: '100%',
height: '64px',
background: theme.palette.background.main,
position: 'fixed',
[theme.breakpoints.up('sm')]: {
height: '64px'
}
},
icon: {
fontSize: '2.5em',
},
title: {
color: theme.palette.primary.dark,
},
content: {
top: '64px',
width: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'flex-start',
top: '64px',
position: 'relative',
},
contentFixed: {
height: 'calc(100vh - 64px)',
},
back: {
zIndex: 10,
border: 'none',
padding: theme.spacing(0.2),
textAlign: 'center',
textDecoration: 'none',
borderRadius: '50%',
position: 'absolute',
left: theme.spacing(1),
},
retour:{
fontFamily: 'Roboto',
color: '#1E2327',
fontSize: '0.8rem',
fontWeight: '500',
},
popup:{
fontFamily: 'Roboto',
color: '#1E2327',
fontSize: '0.8rem',
fontWeight: '500',
}
});
class LayoutBack extends Component {
constructor(props) {
super(props);
}
state = {
open: false,
};
openDialog() {
this.setState({ open: true });
}
closeDialog() {
this.setState({ open: false });
}
refreshDialog() {
this.setState({ open: false });
window.location.reload();
}
// Add a listener to prevent browser page refresh
componentWillMount() {
if (typeof window !== "undefined") {
window.onbeforeunload = (e) => {
console.log('Stop this');
// this.openDialog();
e.preventDefault()
e.returnValue = '';
};
}
}
// Clear listener
componentWillUnmount() {
window.onbeforeunload = null
}
render() {
const { classes, height} = this.props;
//height fixed = height 100vh
var openStudio = this.props.openStudio ? 1 : 0;
const content = (height == 'fixed') ? classes.content+' '+classes.contentFixed : classes.content
return (
<RootContainer align='center'>
<div id="H" className={classes.head}>
<div className={classes.inner}>
<ButtonBase name='back'
focusRipple
className={classes.back}
focusVisibleClassName={classes.focusVisible}
>
<ArrowLeft color="primary" classes={{ root: classes.icon }}></ArrowLeft>
{/* <Hidden mdUp className={classes.retour}></Hidden> */}
<Hidden smDown className={classes.retour}>
<div onClick={this.props.step==1 || openStudio==1 ? this.openDialog.bind(this) : () => Router.back()}>Retour</div>
</Hidden>
<Dialog open={this.state.open}>
<DialogTitle className={classes.popup}> Souhaitez-vous poursuivre votre candidature ?</DialogTitle>
<DialogContent className={classes.popup}> Si vous cliquez sur le bouton Supprimer, tous les éléments associés à votre candidature (vidéo, CV) seront définitivement supprimés. </DialogContent>
<DialogActions className={classes.popup}>
<Button onClick={this.refreshDialog.bind(this)} >
Supprimer
</Button>
<Button onClick={this.closeDialog.bind(this)} autoFocus>
Poursuivre
</Button>
</DialogActions>
</Dialog>
</ButtonBase>
<Typography
component="h1"
align="center"
className={classes.title}
>
{this.props.text}
</Typography>
</div>
</div>
<div id="C" className={content}>
{this.props.children}
</div>
</RootContainer>
)
}
}
LayoutBack.defaultProps = {
step: 0,
openStudio:false
}
export default withStyles(styles)(LayoutBack)
@@ -1,105 +0,0 @@
import { withStyles } from '@material-ui/core/styles'
import Router from 'next/router';
import RootContainer from '../atoms/RootContainer'
import ButtonBase from "@material-ui/core/ButtonBase";
import Close from '@material-ui/icons/Close';
import Typography from '@material-ui/core/Typography';
const styles = theme => ({
inner: {
height: '100%',
position: 'relative',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
// boxShadow: '0 6px 10px 0 rgba(0, 0, 0, 0.04), 0 1px 10px 0 rgba(0, 0, 0, 0.04), 0 3px 5px -1px rgba(0, 0, 0, 0.04)',
backgroundColor: '#1E2327',
right:'30px'
},
head: {
zIndex: '999',
width: '100%',
height: '100px',
backgroundColor: '#1E2327',
position: 'fixed',
[theme.breakpoints.up('sm')]: {
height: '100px'
}
},
icon: {
fontSize: '3em',
textAlign :'right',
top:'30px',
right:'30px',
color:'#fff',
margin:'20px'
},
title: {
color: theme.palette.primary.dark,
},
content: {
top: '100px',
width: '100%',
minHeight: '1000px',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'flex-start',
position: 'relative',
backgroundColor: '#1E2327',
},
contentFixed: {
height: 'calc(100vh - 100px)',
backgroundColor: '#1E2327',
},
back: {
zIndex: 10,
border: 'none',
padding: theme.spacing(0.2),
textAlign: 'center',
textDecoration: 'none',
borderRadius: '50%',
position: 'absolute',
right: theme.spacing(1),
backgroundColor: '#34383C'
},
player: {
background:'#1E2327'
},
});
function LayoutBack(props) {
const { classes, height} = props;
//height fixed = height 100vh
const content = (height == 'fixed') ? classes.content+' '+classes.contentFixed : classes.content
return (
<RootContainer align='center' className={content}>
<div id="H" className={classes.head}>
<div className={classes.inner}>
<ButtonBase name='back'
focusRipple
className={classes.back}
focusVisibleClassName={classes.focusVisible}
onClick={() => Router.push(props.url)}>
<Close color="#fff" classes={{ root: classes.icon }}></Close>
</ButtonBase>
<Typography
component="h1"
align="center"
className={classes.title}
>
{props.text}
</Typography>
</div>
</div>
<div id="C" className={content}>
{props.children}
</div>
</RootContainer>
)
}
export default withStyles(styles)(LayoutBack)
@@ -1,120 +0,0 @@
import React, { Fragment, useState } from 'react';
import { withStyles } from '@material-ui/core/styles'
import RootContainer from '../atoms/RootContainer'
import Header from '../organisms/Header'
import TextField from '@material-ui/core/TextField';
import IconAdd from '@material-ui/icons/Add';
import { Button } from '@material-ui/core';
const styles = theme => ({
head: {
width: '100%',
height: '64px',
background: theme.palette.secondary.main,
position: 'fixed',
zIndex: '999',
},
foot: {
height: '64px',
width: '100%',
position: 'relative',
boxShadow: '0px 0px 10px rgba(30, 35, 39, 0.10)',
},
content: {
top: '64px',
height: 'calc(100vh - 64px)',
position: 'relative',
},
filterForm: {
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
backgroundColor: theme.palette.input.main,
position: 'absolute',
bottom: 0,
left: 0,
width: '100% !important',
},
textField: {
textAlign: 'center',
justifyContent: 'center',
margin: 0,
'& input': {
fontWeight: '300',
color: theme.palette.primary.dark,
backgroundColor: theme.palette.input.main,
minWidth: '65vw',
padding: 0,
margin: 0,
paddingLeft: theme.spacing(2),
}
},
});
const chatSubmit = () => {
}
function LayoutCandidature(props) {
const { classes, children } = props;
const [text, setText] = useState("");
const [displayMessageBar, toggleMessageBar] = useState(false);
const handleChange = (v) => {
toggleMessageBar(v)
}
const toggleDisplay = (v) => {
toggleMessageBar(v)
}
return (
<RootContainer>
<div id="H" className={classes.head}>
<div className={classes.inner}>
<Header searchBar={true} />
</div>
</div>
<div id="C" className={classes.content}>
{
React.Children.map(props.children, child => {
return React.cloneElement(child, { toggleMessageBar: handleChange });
})
}
</div>
{displayMessageBar &&
(<section id="F" className={classes.foot}>
<div className={classes.filterForm}>
<TextField
id="standard-search"
name="chattext"
value={text}
onChange={(e) => setText(e.target.value)}
placeholder={"Message"}
className={classes.textField}
InputLabelProps={{
shrink: true,
}}
// margin="dense"
//variant="filled"
onKeyPress={(ev) => {
if (ev.key === 'Enter') {
// Do code here
chatSubmit()
}
}}
/>
<Button onClick={chatSubmit}
variant="contained"
className={classes.button}>
<IconAdd />
</Button >
</div>
</section>)}
</RootContainer>
)
}
export default withStyles(styles)(LayoutCandidature)
@@ -1,142 +0,0 @@
import { withStyles } from '@material-ui/core/styles'
import PropTypes from 'prop-types';
import { Button } from '@material-ui/core';
import Router from 'next/router';
import RootContainer from '../atoms/RootContainer'
import ButtonBase from "@material-ui/core/ButtonBase";
import ArrowLeft from '@material-ui/icons/KeyboardArrowLeft';
import HideOnScroll from '../atoms/CollapsibleBack';
import SocialShare from '../organisms/SocialShare'
import withWidth, { isWidthUp } from '@material-ui/core/withWidth'
import HeaderEntreprise from '../organisms/HeaderPersonnalise'
import {AppBar,CssBaseline,Container,Toolbar,IconButton,Typography} from "@material-ui/core";
import Hidden from '@material-ui/core/Hidden';
import Link from 'next/link'
const styles = theme => ({
RootContainer: {
padding: 0,
margin: 0,
maxWidth: 'inherit',
},
appBar: {
backgroundColor: 'transparent',
boxShadow: 'none',
},
foot: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
position: 'fixed',
bottom: 0,
padding: theme.spacing(1.2, 0),
backgroundColor: theme.palette.secondary.main,
boxShadow: '0px 0px 10px rgba(30, 35, 39, 0.10)',
},
content: {
height: 'calc(100vh - 64px)',
[theme.breakpoints.up('sm')]: {
height: 'calc(100vh - 64px)',
},
position: 'relative',
paddingBottom: '10vh',
},
back: {
alignSelf: 'flex-start',
position: 'absolute',
zIndex: '999',
color: 'white',
backgroundColor: theme.palette.menu.backArrow,
border: 'none',
color: 'white',
padding: theme.spacing(0.2),
textAlign: 'center',
textDecoration: 'none',
display: 'inlineBlock',
margin: theme.spacing(2),
borderRadius: '50%',
},
icon: {
fontSize: '2.5em',
},
rootButton: {
'&:hover': {
backgroundColor: theme.palette.primary.important + '!important',
},
},
button: {
textTransform: 'inherit',
marginLeft: theme.spacing(1),
marginRight: theme.spacing(1),
padding: theme.spacing(1.2, 2),
color: theme.palette.secondary.main,
backgroundColor: theme.palette.primary.important,
textDecoration:'none',
},
voirOffre: {
textTransform: 'inherit',
marginLeft: theme.spacing(1),
marginRight: theme.spacing(1),
padding: theme.spacing(1.2, 2),
color: '#BBBCBD',
backgroundColor: '#F3F3F4',
},
lien:{
textDecoration:'none',
color:'#fff'
},
})
function LayoutCompany(props) {
const { classes, companyId, companyLibelle } = props;
const socialShareUrl = typeof window !== 'undefined' ? window.location : publicRuntimeConfig.frontServerUrl + `/Entreprise/${companyId}-${_.kebabCase(companyLibelle)}`;
return (
<RootContainer>
<HeaderEntreprise retour="Entreprises" menu="Entreprises"/>
<div id="C" className={classes.content}>
{props.children}
</div>
<Hidden mdUp>
<div id="F" className={classes.foot}>
<Button
variant="contained"
className={classes.button + ' cypButtonApply'}
classes={{ root: classes.rootButton}}
>
<a href={`/Reponse?companyId=${companyId}`} className={classes.lien }>Postuler</a>
</Button>
<SocialShare url={socialShareUrl} />
{/* <Link href="#discover" >
<Button
variant="contained"
className={classes.voirOffre + ' cypButtonApply'}
>Voir les offres</Button>
</Link> */}
{/* <a
href={`/Reponse?companyId=${companyId}`}
variant="contained"
className={classes.button}
classes={{ root: classes.rootButton }}
// onClick={() => Router.push(`/Reponse?companyId=${companyId}`)}
>
Candidature spontanée</a> */}
</div>
</Hidden>
</RootContainer>
)
}
LayoutCompany.propTypes = {
classes: PropTypes.object.isRequired,
company: PropTypes.object,
};
export default withStyles(styles)(withWidth()(LayoutCompany))
+18 -20
View File
@@ -1,15 +1,17 @@
import PropTypes from "prop-types";
import { withStyles } from '@material-ui/core/styles'
import Header from '../organisms/Header'
import RootContainer from '../atoms/RootContainer'
import Footer from '../organisms/Footer';
const styles = theme => ({
root: {
height: '100%'
},
head: {
width: '100%',
zIndex: '999',
height: '64px',
background: theme.palette.secondary.main,
height: '56px',
background: 'silver',
position: 'fixed',
[theme.breakpoints.up('sm')]: {
@@ -18,17 +20,16 @@ const styles = theme => ({
},
content: {
background: theme.palette.background.grid,
top: '64px',
top: '56px',
height: 'calc(100vh - 56px)',
[theme.breakpoints.up('sm')]: {
top: '64px',
height: 'calc(100vh - 64px)',
},
position: 'relative',
overflow: 'auto',
},
footer: {
marginTop: theme.spacing(10),
},
}
});
function LayoutGrid(props) {
@@ -36,28 +37,25 @@ function LayoutGrid(props) {
const { classes } = props;
return (
<RootContainer>
<div className={classes.root}>
<div id="H" className={classes.head}>
<div className={classes.inner}>
<Header backLink={props.backLink} />
<Header backLink={props.backLink}/>
</div>
</div>
<div id="C" className={classes.content}>
{props.children}
</div>
<div id="F" className={classes.footer}>
<Footer />
</div>
</RootContainer>
</div>
)
}
LayoutGrid.defaultProps = {
backLink: "/"
backLink:"/"
}
LayoutGrid.propTypes = {
backLink: PropTypes.string
backLink : PropTypes.string
}
export default withStyles(styles)(LayoutGrid)
+46 -116
View File
@@ -1,151 +1,81 @@
import { withStyles } from '@material-ui/core/styles'
import PropTypes from 'prop-types';
import Header from '../organisms/Header'
import { Button } from '@material-ui/core';
import Router from 'next/router';
import RootContainer from '../atoms/RootContainer'
import ButtonBase from "@material-ui/core/ButtonBase";
import ArrowLeft from '@material-ui/icons/KeyboardArrowLeft';
import HeaderPersonnalise from '../organisms/HeaderPersonnalise'
import SocialShare from '../organisms/SocialShare'
import withWidth, { isWidthUp } from '@material-ui/core/withWidth'
import Hidden from '@material-ui/core/Hidden';
import Link from 'next/link'
import getConfig from 'next/config'
import _ from "lodash/string";
const { publicRuntimeConfig } = getConfig()
import ArrowLeft from '@material-ui/icons/keyboardArrowLeft';
const styles = theme => ({
root: {
height: '100%'
},
foot: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
position: 'fixed',
bottom: 0,
padding: theme.spacing(1.2, 0),
backgroundColor: theme.palette.secondary.main,
boxShadow: '0px 0px 10px rgba(30, 35, 39, 0.10)',
[theme.breakpoints.up('sm')]: {
height: '64px'
},
},
lien:{
textDecoration:'none',
color:'#fff'
},
contentDefault: {
height: 'auto',
position: 'relative',
paddingBottom: '10vh',
},
contentProvided: {
height: '100%',
content: {
height: 'calc(100vh - 56px)',
[theme.breakpoints.up('sm')]: {
height: 'calc(100vh - 64px)',
},
position: 'relative',
overflow: 'auto',
},
back:
{
alignSelf: 'flex-start',
position: 'absolute',
zIndex: '999',
color: 'white',
backgroundColor: theme.palette.menu.backArrow,
zIndex:10,
color : 'white',
backgroundColor: 'grey',
border: 'none',
color: 'white',
padding: theme.spacing(0.2),
padding: '10px',
textAlign: 'center',
textDecoration: 'none',
display: 'inlineBlock',
margin: theme.spacing(2),
fontSize: '38px',
margin:' 10px 16px',
borderRadius: '50%',
},
icon: {
fontSize: '2.5em',
},
rootButton: {
'&:hover': {
backgroundColor: theme.palette.primary.important + '!important',
},
},
button: {
textTransform: 'inherit',
marginLeft: theme.spacing(4.5),
marginRight: theme.spacing(4.5),
padding: theme.spacing(1.2, 2),
color: theme.palette.secondary.main,
backgroundColor: theme.palette.primary.important,
},
voirEntreprise: {
textTransform: 'inherit',
marginLeft: theme.spacing(1),
marginRight: theme.spacing(1),
padding: theme.spacing(1.2, 2),
color: '#BBBCBD',
backgroundColor: '#F3F3F4',
},
pourvuButton:{
padding :'10px',
textTransform: 'inherit',
},
}
})
function LayoutOffre(props) {
function Layout(props) {
const { classes } = props;
const { classes, offreId, offre, isProvided } = props;
const contentClass = (!isProvided) ? classes.contentDefault : classes.contentProvided
const socialShareUrl = typeof window !== 'undefined' ? window.location : publicRuntimeConfig.frontServerUrl + `/Offre/${offreId}-${_.kebabCase(offre.title)}`;
return (
<RootContainer>
<HeaderPersonnalise retour="Offres" menu="Offres d'emploi"/>
<div id="C" className={contentClass}>
<div className={classes.root}>
<ButtonBase name='back'
focusRipple
className={classes.back}
focusVisibleClassName={classes.focusVisible}
onClick={() => Router.back()}>
<ArrowLeft></ArrowLeft>
</ButtonBase>
<div id="C" className={classes.content}>
{props.children}
</div>
<Hidden mdUp>
{!isProvided && (
<div id="F" className={classes.foot}>
{/* <div className={classes.inner}>
<div id="F" className={classes.foot}>
{/* <div className={classes.inner}>
<div className={classes.grow} /> */}
{/* <Link href={`/Entreprise/${offre.company.id}-${_.kebabCase(offre.company.brand_name)}`} >
<Button
variant="contained"
className={classes.voirEntreprise + ' cypButtonApply'}
>Voir l'entreprise</Button>
</Link> */}
<Button
variant="contained"
className={classes.button + ' cypButtonApply'}
classes={{ root: classes.rootButton}}
>
<a href={`/Reponse?adId=${offreId}`} className={classes.lien }>Postuler</a>
</Button>
<SocialShare url={socialShareUrl} />
{/* <div className={classes.grow} />
<Button variant="outlined" color="secondary" >Postuler</Button>
{/* <div className={classes.grow} />
</div> */}
</div>
)}
{isProvided && (
<div id="F" className={classes.foot}>
{/* <div className={classes.inner}>
<div className={classes.grow} /> */}
<Button variant="contained" disabled className={classes.pourvuButton}>
Offre pourvue
</Button>
{/* <div className={classes.grow} />
</div> */}
</div>
)}
</Hidden>
</div>
</RootContainer>
</div>
)
}
LayoutOffre.propTypes = {
classes: PropTypes.object.isRequired,
offre: PropTypes.object,
};
export default withStyles(styles)(LayoutOffre)
export default withStyles(styles)(Layout)
+97 -25
View File
@@ -1,29 +1,101 @@
import React, { Fragment } from 'react'
import CircularProgress from '@material-ui/core/CircularProgress'
import { withStyles } from '@material-ui/core/styles'
const styles = theme => ({
loader: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
textAlign: 'center',
justifyContent: 'center',
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
fontWeight: '500',
fontSize: '1em',
padding: theme.spacing(6,0),
color: theme.palette.primary.main,
},
})
import React from 'react'
class Loader extends React.Component {
export default class extends React.Component {
render() {
const { classes } = this.props;
return (
<div className={classes.loader + ' ' + 'alert alert-info'}><CircularProgress color="primary" />Chargement... </div>
)
if (this.props.fullscreen) {
return (
<React.Fragment>
<style jsx global>{`
.circle-loader {
position: absolute;
top: 50%;
left: 50%;
width: 50%;
z-index: 100;
text-align: center;
transform: translate(-50%, -50%);
}
.circle-loader .circle {
fill: transparent;
stroke: rgba(0,0,0,0.2);
stroke-width: 4px;
animation: dash 2s ease infinite, rotate 2s linear infinite;
}
@keyframes dash {
0% {
stroke-dasharray: 1,95;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 85,95;
stroke-dashoffset: -25;
}
100% {
stroke-dasharray: 85,95;
stroke-dashoffset: -93;
}
}
@keyframes rotate {
0% {transform: rotate(0deg); }
100% {transform: rotate(360deg); }
}
`}</style>
<span className="circle-loader">
<svg className="circle" width="60" height="60" version="1.1" xmlns="http://www.w3.org/2000/svg">
<circle cx="30" cy="30" r="15"/>
</svg>
</span>
</React.Fragment>
)
} else {
return (
<React.Fragment>
<style jsx global>{`
.circle-loader {
display: block;
text-center;
padding-left: 50%;
}
.circle-loader .circle {
position: relative;
left: -30px;
fill: transparent;
stroke: rgba(0,0,0,0.2);
stroke-width: 4px;
animation: dash 2s ease infinite, rotate 2s linear infinite;
}
@keyframes dash {
0% {
stroke-dasharray: 1,95;
stroke-dashoffset: 0;
}
50% {
stroke-dasharray: 85,95;
stroke-dashoffset: -25;
}
100% {
stroke-dasharray: 85,95;
stroke-dashoffset: -93;
}
}
@keyframes rotate {
0% {transform: rotate(0deg); }
100% {transform: rotate(360deg); }
}
`}</style>
<span className="circle-loader">
<svg className="circle" width="60" height="60" version="1.1" xmlns="http://www.w3.org/2000/svg">
<circle cx="30" cy="30" r="15"/>
</svg>
</span>
</React.Fragment>
)
}
}
}
export default withStyles(styles)(Loader)
}
@@ -1,55 +0,0 @@
import React, { Fragment } from 'react'
import CircularProgress from '@material-ui/core/CircularProgress'
import { withStyles } from '@material-ui/core/styles'
import LinearProgress from '@material-ui/core/LinearProgress';
const styles = theme => ({
loader: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
textAlign: 'center',
justifyContent: 'center',
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
fontWeight: '500',
fontSize: '1em',
padding: theme.spacing(6,0),
margin:'50px 0',
},
loaderGras:{
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
paddingTop:'10px',
fontSize: '1.875em',
fontWeight: '500',
marginBottom:'30px',
},
loaderSecondaire:{
fontFamily: '"Roboto", "Helvetica", "Arial", "sans-serif"',
fontSize: '1em',
fontWeight: '300',
},
root: {
top:"200px",
width: '100%',
'& > * + *': {
marginTop: theme.spacing(2),
},
},
})
class LoaderVideo extends React.Component {
render() {
const { classes, textePrincipal, texteSecondaire } = this.props;
return (
<div className={classes.root}>
<div className={classes.loader }><CircularProgress color="primary" /><span className={classes.loaderGras }>{textePrincipal}</span><br/><span className={classes.loaderSecondaire }> {texteSecondaire}</span><br/></div>
<div >
</div>
</div>
)
}
}
export default withStyles(styles)(LoaderVideo)
-10
View File
@@ -1,10 +0,0 @@
{
"baseUrl": "http://localhost:8000/",
"env":{
"nom":"toto",
"prenom": "toto",
"email":"thomasberrodedeclic42@gmail.com",
"password": "123456"
},
"chromeWebSecurity": false
}
Binary file not shown.
@@ -1,28 +0,0 @@
describe('RegisterTest', function() {
before(function(){
cy.exec('yarn dropAndCreateDB',{failOnNonZeroExit: false});
})
it('Test if Register works', function() {
cy.viewport(375, 667)
cy.visit('/')
cy.get('.cypConnexionMenu').click()
cy.get('.cypRegister').click({ force: true })
cy.url().should('contain', 'Login')
cy.get('#nom').type(Cypress.env('nom'))
cy.get('#prenom').type(Cypress.env('prenom'))
cy.get('#emailRegister').type(Cypress.env('email'))
cy.get('#adornment-password').type(Cypress.env('password'))
cy.get('#cypCheckboxRegister').check()
cy.get('.cypButtonRegister').click().wait(3000)
cy.url().should('contain','VerifyEmail')
cy.get('span').should('contain',Cypress.env('email'))
})
})
@@ -1,54 +0,0 @@
// describe('ConfirmMailTest', function() {
// it("Register Form: Email is delievered", function() {
// const incoming_mailbox = `thomasberrodedeclic42@gmail.com`;
// cy
// .task("gmail:check", {
// from: "noreply@talentstube.com",
// to: incoming_mailbox,
// subject: `Bienve nue ${incoming_mailbox} 🔑`
// })
// .then(email => {
// assert.isNotNull(email, `Email was not found`);
// });
// });
// })
describe("Email assertion:", () => {
it("Look for an email with specific subject and link in email body", function() {
// debugger; //Uncomment for debugger to work...
cy.wait(5000)
cy
.task("gmail:get-messages", {
options: {
include_body: true,
}
})
.then(emails => {
const found_email = emails.find(email => {
return (
email.from.indexOf("noreply@talentstube.com") >= 0 &&
email.subject.indexOf("Bienvenue thomasberrodedeclic42@gmail.com 🔑") >= 0
);
});
assert.isNotNull(found_email, "Found email👍");
const body = found_email.body.text;
assert.isTrue(
body.indexOf(
"http://localhost:8000/ConfirmAccount/"
) >= 0,
"Found reset link👍"
);
var startUrl = body.indexOf("http://");
var endUrl = body.indexOf("*");
var link = body.substring(startUrl, endUrl);
cy.visit(link);
cy.get('p').should('contain','e-mail validé')
});
});
});
@@ -1,38 +0,0 @@
describe('Visit the whole site as anonymous', function() {
it('visit the whole site to see if errors', function() {
cy.viewport(375, 667)
//Page d'accueil
cy.visit('/')
cy.get('p').should('contain', 'à la une')
cy.get('.cypConnexionMenu').click()
cy.get('span').should('contain', 'Connexion')
cy.get('body').click('left')
cy.get('button').first().click()
cy.get('span').should('contain', 'Accueil')
//Page de Login
cy.visit('/Login')
cy.get('.cypButtonConnexion').should('exist')
cy.get('.cypLinkedInConnexion').should('exist')
//Page d'offre(s)
cy.visit('/Offres')
cy.get('h1').should('contain', 'offres d\'emploi vidéo en cours')
cy.get('.cypCardOffre').first().click()
cy.get('.cypButtonApply').should('exist')
cy.get('p').should('contain','Détails de l\'offre d\'emploi')
cy.get('.player').should('exist')
//Page des entreprises
cy.visit('/Entreprises')
cy.get('.cypCardCompany').last().click()//could use .eq(2) instead of .last()
cy.get('.player').should('exist')
//Help
cy.visit('/Help')
cy.get('h1').should('contain','Comment ça marche')
})
})
@@ -1,13 +0,0 @@
describe('Wrong Login Test', function() {
it('Teste la connexion d\'un utilisateur', function() {
cy.viewport(375, 667)
cy.visit('/')
cy.get('.cypConnexionMenu').click()
cy.get('.cypConnexion').click({ force: true })
cy.url().should('contain', 'Login')
cy.get('.cypInputEmail input').type('wrongmail@wrong.fr')
cy.get('.cypInputPassword input').type('wrongpassword')
cy.get('.cypButtonConnexion').click()
cy.get('#client-snackbar').should('contain','Mauvais identifiants')
})
})
@@ -1,31 +0,0 @@
describe('Apply to an offer', function() {
it('Go to an offer and apply to it', function() {
cy.viewport(375, 667)
cy.visit('/')
cy.get('.cypConnexionMenu').click()
cy.get('.cypConnexion').click({ force: true })
cy.url().should('contain', 'Login')
cy.get('.cypInputEmail input').type(Cypress.env('email'))
cy.get('.cypInputPassword input').type(Cypress.env('password'))
cy.get('.cypButtonConnexion').click().wait(3000)
cy.get('.cypButtonOffers').click().wait(3000)
cy.url().should('contain', 'Offres')
cy.get('.cypCardOffre').first().click().wait(3000)
cy.url().should('contain', 'Offre')
cy.get('.cypButtonApply').first().click().wait(3000)
cy.url().should('contain', 'Reponse')
cy.fixture('cypVid.mov', 'base64').then(fileContent => {
cy.get('.cypButtonImportVid').invoke('show').upload(
{ fileContent, fileName: 'cypVid.mov', mimeType: 'video/quicktime', encoding: 'base64' },
{ subjectType: 'input', force: true }
)}).wait(3000)
cy.get('.cypButtonSendApplication').click().wait(3000)
})
//Should verify if application is received
})
@@ -1,14 +0,0 @@
describe('ConnexionTest', function() {
it('Test login', function() {
cy.viewport(375, 667)
cy.visit('/')
cy.get('.cypConnexionMenu').click()
cy.get('.cypConnexion').click({ force: true })
cy.url().should('contain', 'Login')
cy.get('.cypInputEmail input').type(Cypress.env('email'))
cy.get('.cypInputPassword input').type(Cypress.env('password'))
cy.get('.cypButtonConnexion').click().wait(3000)
cy.get('.cypConnexionMenu').click()
cy.get('h3').should('contain', Cypress.env('email') )
})
})
@@ -1,17 +0,0 @@
describe('VisitAsUser', function() {
it('Test if user can access to his pages', function() {
cy.viewport(375, 667)
cy.visit('/')
cy.get('.cypConnexionMenu').click()
cy.get('.cypConnexion').click({ force: true })
cy.url().should('contain', 'Login')
cy.get('.cypInputEmail input').type(Cypress.env('email'))
cy.get('.cypInputPassword input').type(Cypress.env('password'))
cy.get('.cypButtonConnexion').click().wait(3000)
cy.visit('/Candidatures')
// cy.get('h1').should('contain', Cypress.env('Mes candidatures') )
})
})
@@ -1,17 +0,0 @@
describe('test_name', function() {
it('what_it_does', function() {
cy.viewport(1536, 674)
cy.visit('http://localhost:8000/')
cy.get('.MuiList-root > div > .jss56:nth-child(1) > .MuiListItemText-root > .MuiTypography-root').click()
cy.get('.MuiList-root > div > .jss56:nth-child(2) > .MuiListItemText-root > .MuiTypography-root').click()
cy.get('.MuiList-root > div > .jss56:nth-child(3) > .MuiListItemText-root > .MuiTypography-root').click()
})
})
-1
View File
@@ -1 +0,0 @@
{"installed":{"client_id":"438657734125-poo68tqp3dosq2od8udgipdqietbav0d.apps.googleusercontent.com","project_id":"tt-app-251309","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"m_zcFplh1LZlMHl6bwkBBFl8","redirect_uris":["http://localhost"],"javascript_origins":["http://localhost"]}}
-1
View File
@@ -1 +0,0 @@
{"access_token":"ya29.Glt0B7O-MEh7BOQ6yJyZY1628D2mH1lbVz7LaJfiUgKJJv5mt1DljeQsZU49z-5F9GYsWVn0E5ylYj2yWuGLGb2J0sZJjVUWMLYn333dRbk-0469E08Hmc3GkIOO","refresh_token":"1/42U4Ny2XVLbf3D3xO4S2bwyyX183RuqQ2kcBmND7hpr5japueYf6psdLEWzIFfCx","scope":"https://www.googleapis.com/auth/gmail.readonly","token_type":"Bearer","expiry_date":1567156006741}
-52
View File
@@ -1,52 +0,0 @@
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
const gmail = require("gmail-tester");
const path = require("path");
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
on("before:browser:launch", (browser = {}, args) => {
if (browser.name === "chrome") {
args.push("--remote-debugging-port=9221");
return args;
}
});
// on("task", {
// "gmail:check": async args => {
// const { from, to, subject } = args;
// const email = await gmail.check_inbox(
// path.resolve(__dirname, "credentials.json"), // credentials.json is inside plugins/ directory.
// path.resolve(__dirname, "gmail_token.json"), // gmail_token.json is inside plugins/ directory.
// subject,
// from,
// to,
// 10, // Poll interval (in seconds)
// 30 // Maximum poll interval (in seconds). If reached, return null, indicating the completion of the task().
// );
// return email;
// }
// });
on("task", {
"gmail:get-messages": async args => {
const messages = await gmail.get_messages(
path.resolve(__dirname, "credentials.json"),
path.resolve(__dirname, "gmail_token.json"),
args.options
);
return messages;
}
});
}
File diff suppressed because one or more lines are too long
Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

-46
View File
@@ -1,46 +0,0 @@
// ***********************************************
// This example commands.js shows you how to
// create various custom commands and overwrite
// existing commands.
//
// For more comprehensive examples of custom
// commands please read more here:
// https://on.cypress.io/custom-commands
// ***********************************************
//
//
// -- This is a parent command --
// Cypress.Commands.add("login", (email, password) => { ... })
//
//
// -- This is a child command --
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
//
//
// -- This is a dual command --
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
//
//
// -- This is will overwrite an existing command --
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
import 'cypress-file-upload';
Cypress.Commands.add('login', () => {
cy.viewport(375, 667)
cy.visit('/')
cy.request({
method: 'POST',
url: 'http://localhost/api/login_check',
body: {
username: 'cypress.tt.edeclic@gmail.com',
password: 'qJxY4kovD13W'
}
})
.then((resp) => {
window.localStorage.setItem('ttJWT', resp.body.token)
})
})
-31
View File
@@ -1,31 +0,0 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands'
// Alternatively you can use CommonJS syntax:
// require('./commands')
// before(() => {
// cy.exec('yarn dropAndCreateDB');
// })
Cypress.on('uncaught:exception', (err, runnable) => {
// returning false here prevents Cypress from
// failing the test
return false
})

Some files were not shown because too many files have changed in this diff Show More