Compare commits

...

48 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
Sébastien GLATZ 9becfbe2fc Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-06-27 11:12:46 +02:00
Sébastien GLATZ e27d66dc3d Add component IconText 2019-06-27 11:12:38 +02:00
Sébastien GLATZ 1e83e98042 Add new theme color 2019-06-27 11:12:06 +02:00
Sébastien GLATZ a18c9fd223 Trim App logo 2019-06-27 11:11:36 +02:00
Sébastien GLATZ c41716d0e4 Update style HomePage 2019-06-27 11:11:16 +02:00
Thomas Berrod 4521fbb868 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga
# Conflicts:
#	nextjs/pages/index.js
2019-06-27 09:29:21 +02:00
Thomas Berrod 13cba95879 english renaming 2019-06-27 09:21:21 +02:00
Thomas Berrod 9f7a319913 register form 2019-06-26 17:28:38 +02:00
Sébastien GLATZ 3cd2a61276 Merge branch 'Saga' of https://git.e-declic.net/talents-tube/app into Saga 2019-06-26 16:14:27 +02:00
Sébastien GLATZ 6fca2f5435 Add searchBar to Header 2019-06-26 16:14:22 +02:00
Sébastien GLATZ d4da57b006 Update style and semantics 2019-06-26 16:13:39 +02:00
Sébastien GLATZ ef41f9ddd3 Decomposition of Tile from HorizontalScroller 2019-06-26 16:11:12 +02:00
Sébastien GLATZ 5066a73313 Factorization HorizontalScroller 2019-06-26 16:09:11 +02:00
Sébastien GLATZ a502dc944f Evolution home page 2019-06-26 16:05:53 +02:00
Sébastien GLATZ a847305b4a Evolution style thème 2019-06-26 16:05:10 +02:00
Sébastien GLATZ 5405603c70 Changement logo AppBar 2019-06-26 16:04:50 +02:00
Sébastien GLATZ f7ef867b5a Changement logo AppBar 2019-06-26 12:15:57 +02:00
Thomas Berrod 6e427e6713 newsletter + register begining 2019-06-25 17:34:06 +02:00
Thomas Berrod 17aa918c89 supress image dir 2019-06-25 11:19:08 +02:00
Thomas Berrod 34df2c28a5 swipable Login REgister 2019-06-24 17:45:15 +02:00
Thomas Berrod 3c92605ca3 offres: button back 2019-06-24 16:46:04 +02:00
Thomas Berrod e2ade8dc6f centrage du btn postuler 2019-06-24 16:13:23 +02:00
Thomas Berrod 973603fef0 app bar responsiveness 2019-06-21 16:25:04 +02:00
Thomas Berrod 7e2886219f Mes candidatures setup 2019-06-21 16:09:34 +02:00
Thomas Berrod 54ea1f7ac5 login drawer 2019-06-21 15:55:33 +02:00
Thomas Berrod 55322567ae added companies company 2019-06-20 17:04:04 +02:00
Thomas Berrod 177bf112aa video rotator with labels 2019-06-19 15:05:37 +02:00
Thomas Berrod 3701577e3b index video rotator beta 2019-06-19 14:56:22 +02:00
Thomas Berrod 7329256a9f menu skeleton 2019-06-19 11:00:38 +02:00
Thomas Berrod 8bcd62519d fb + linkedin working 2019-06-18 18:01:06 +02:00
Thomas Berrod 62c118519e facebook passport first integration 2019-06-07 17:02:44 +02:00
Thomas Berrod f8e55d7466 login JWT storage 2019-06-07 11:13:48 +02:00
Thomas Berrod a88f8dd7e5 try reducer serving old data before fetch 2019-06-06 17:42:37 +02:00
Thomas Berrod 14a90e3aac variant deprecation fix 2019-06-06 16:49:53 +02:00
Thomas Berrod 4734b10243 recorder integration 2019-06-06 16:45:54 +02:00
Thomas Berrod ac90054670 Merge branch 'master' into Saga
# Conflicts:
#	nextjs/pages/Login.js
2019-06-06 10:37:59 +02:00
Thomas Berrod 014184509b comment 2019-06-05 09:23:25 +02:00
Thomas Berrod d73655af40 gitignore not ignored 2019-06-04 11:49:51 +02:00
Thomas Berrod e33f43e86a node_modules hell 2019-06-04 11:49:37 +02:00
Thomas Berrod 4b1c634829 root reducer update 2019-06-04 11:01:02 +02:00
Thomas Berrod 060521f380 grid paging 2019-06-03 18:53:42 +02:00
Thomas Berrod 9a8a2d7728 merge Master on saga 2019-06-03 09:34:43 +02:00
Thomas Berrod 5439b98f15 avancement 2019-05-29 16:00:28 +02:00
Thomas Berrod 2d4ac00df2 avancement Saga 2019-05-28 17:28:03 +02:00
Thomas Berrod 15c612c2ca login roundtrip 2019-05-27 18:36:27 +02:00
Thomas Berrod dd47a62655 saga 2019-05-27 14:22:27 +02:00
34305 changed files with 9679 additions and 2734871 deletions
+3 -2
View File
@@ -1,3 +1,4 @@
nextjs/node_modules/
/nextjs/node_modules/
/node_modules/
/nextjs/node_modules/
/nextjs/node_modules/
/jenkins/
-3
View File
@@ -1,3 +0,0 @@
{
"presets": ["next/babel"]
}
+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
+4 -1
View File
@@ -1 +1,4 @@
/.next
/node_modules/
.next/
.gitignore
+4
View File
@@ -20,3 +20,7 @@ yarn dev
## The framework used
[Next.js](https://github.com/zeit/next.js) is a framework for server-rendered React apps.
[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
+63
View File
@@ -0,0 +1,63 @@
import {
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 list
export const fetchAdsRequest = (payload) => ({
type: FETCH_ADS_REQUEST,
payload
});
export const fetchAdsSuccess = res => ({
type: FETCH_ADS_SUCCESS,
res
});
export const fetchAdsFailure = res => ({
type: FETCH_ADS_FAILURE,
res
});
//Ads list
export const fetchPromotedAdsRequest = (payload) => ({
type: FETCH_PROMOTED_ADS_REQUEST,
payload
});
export const fetchPromotedAdsSuccess = res => ({
type: FETCH_PROMOTED_ADS_SUCCESS,
res
});
export const fetchPromotedAdsFailure = res => ({
type: FETCH_PROMOTED_ADS_FAILURE,
res
});
//Single ad
export const fetchAdRequest = payload => ({
type: FETCH_AD_REQUEST,
payload
});
export const fetchAdSuccess = res => ({
type: FETCH_AD_SUCCESS,
res
});
export const fetchAdFailure = res => ({
type: FETCH_AD_FAILURE,
res
});
+48
View File
@@ -0,0 +1,48 @@
import { USER_LOGGED_IN, USER_LOGGED_OUT, REQUEST_LOGIN, REQUEST_LOGIN_FAILURE,
REQUEST_OAUTH_LOGIN, REQUEST_OAUTH_LOGIN_FAILURE,
REQUEST_LOGOUT,
REQUEST_REGISTER, REQUEST_REGISTER_FAILURE
} from "../types";
export const requestLogin = data => ({
type: REQUEST_LOGIN,
data
});
export const userLoggedIn = user => ({
type: USER_LOGGED_IN,
user
});
export const requestLogout = data => ({
type: REQUEST_LOGOUT,
});
export const userLoggedOut = () => ({
type: USER_LOGGED_OUT
});
export const requestLoginFailure = errors => ({
type: REQUEST_LOGIN_FAILURE,
errors
});
export const requestOauthLogin = () => ({
type: REQUEST_OAUTH_LOGIN,
});
export const requestOauthLoginFailure = errors => ({
type: REQUEST_OAUTH_LOGIN_FAILURE,
errors
});
export const requestRegister = data => ({
type: REQUEST_REGISTER,
data
});
export const requestRegisterFailure = errors => ({
type: REQUEST_REGISTER_FAILURE,
errors
});
+23
View File
@@ -0,0 +1,23 @@
import {
FETCH_COMPANIES_REQUEST,
FETCH_COMPANIES_SUCCESS,
FETCH_COMPANIES_FAILURE,
} 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
});
+52
View File
@@ -0,0 +1,52 @@
import {
FETCH_CURRENT_USER_REQUEST,
FETCH_CURRENT_USER_SUCCESS,
FETCH_CURRENT_USER_FAILURE,
SUBSCRIBE_NEWSLETTER_REQUEST,
SUBSCRIBE_NEWSLETTER_SUCCESS,
SUBSCRIBE_NEWSLETTER_FAILURE,
REQUEST_REGISTER,
REQUEST_REGISTER_SUCCESS,
REQUEST_REGISTER_FAILURE
} from '../types'
export const fetchCurrentUserRequest = () => ({
type: FETCH_CURRENT_USER_REQUEST
});
export const fetchCurrentUserSuccess = user => ({
type: FETCH_CURRENT_USER_SUCCESS,
user
});
export const fetchCurrentUserFailure = user => ({
type: FETCH_CURRENT_USER_FAILURE,
user
});
export const registerUserRequest = (payload) => ({
type: REQUEST_REGISTER,
payload
});
export const registerUserSuccess = () => ({
type: REQUEST_REGISTER_SUCCESS,
});
export const registerUserFailure = (err) => ({
type: REQUEST_REGISTER_FAILURE,
err
});
export const subscribeToNewsletterRequest = (payload) => ({
type: SUBSCRIBE_NEWSLETTER_REQUEST,
payload
});
export const subscribeToNewsletterSuccess = () => ({
type: SUBSCRIBE_NEWSLETTER_SUCCESS,
});
export const subscribeToNewsletterFailure = () => ({
type: SUBSCRIBE_NEWSLETTER_FAILURE,
});
+36
View File
@@ -0,0 +1,36 @@
import React, { Fragment } from 'react';
import PropTypes from "prop-types";
import { withStyles } from '@material-ui/core/styles';
import SvgIcon from '@material-ui/core/SvgIcon';
const styles = theme => ({
card: {
display: 'flex',
position: 'relative',
height: '60vh',
width: '100%',
},
});
class IconText extends React.Component {
render() {
return (
<Fragment>
<SvgIcon>
<path d="M20 12l-1.41-1.41L13 16.17V4h-2v12.17l-5.58-5.59L4 12l8 8 8-8z" />
</SvgIcon>
</Fragment>
);
}
}
IconText.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
};
export default withStyles(styles, { withTheme: true })(IconText);
+33
View File
@@ -0,0 +1,33 @@
import { createMuiTheme } from '@material-ui/core/styles';
import red from '@material-ui/core/colors/red';
// Create a theme instance.
const theme = createMuiTheme({
palette: {
primary: {
main: '#155EE4',
},
secondary: {
main: '#19857b',
},
flash: {
main: '#25D89A',
},
error: {
main: red.A400,
},
background: {
default: '#fff',
},
},
overrides: {
MuiPaper: {
elevation1: {
transition: 'box-shadow .25s',
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)',
},
},
},
});
export default theme;
@@ -1,78 +0,0 @@
import React 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 { withStyles } from '@material-ui/core/styles';
import SvgIcon from '@material-ui/core/SvgIcon';
const styles = theme => ({
root: {
width: '100%',
display: 'flex',
},
grow: {
flexGrow: 1,
},
sectionDesktop: {
justifyContent: 'center',
display: 'flex',
},
sectionMobile: {
// display: 'flex',
},
});
class BottomToolBar extends React.Component {
state = {
anchorEl: null,
mobileMoreAnchorEl: null,
};
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<AppBar position="relative">
<Toolbar className={classes.sectionDesktop}>
<div >
<IconButton aria-label="TT">
<SvgIcon>
<path d="M15.94,10.179l-2.437-0.325l1.62-7.379c0.047-0.235-0.132-0.458-0.372-0.458H5.25c-0.241,0-0.42,0.223-0.373,0.458l1.634,7.376L4.06,10.179c-0.312,0.041-0.446,0.425-0.214,0.649l2.864,2.759l-0.724,3.947c-0.058,0.315,0.277,0.554,0.559,0.401l3.457-1.916l3.456,1.916c-0.419-0.238,0.56,0.439,0.56-0.401l-0.725-3.947l2.863-2.759C16.388,10.604,16.254,10.22,15.94,10.179M10.381,2.778h3.902l-1.536,6.977L12.036,9.66l-1.655-3.546V2.778z M5.717,2.778h3.903v3.335L7.965,9.66L7.268,9.753L5.717,2.778zM12.618,13.182c-0.092,0.088-0.134,0.217-0.11,0.343l0.615,3.356l-2.938-1.629c-0.057-0.03-0.122-0.048-0.184-0.048c-0.063,0-0.128,0.018-0.185,0.048l-2.938,1.629l0.616-3.356c0.022-0.126-0.019-0.255-0.11-0.343l-2.441-2.354l3.329-0.441c0.128-0.017,0.24-0.099,0.295-0.215l1.435-3.073l1.435,3.073c0.055,0.116,0.167,0.198,0.294,0.215l3.329,0.441L12.618,13.182z" />
</SvgIcon>
</IconButton>
<IconButton aria-label="TT">
<SvgIcon>
<path d="M18.303,4.742l-1.454-1.455c-0.171-0.171-0.475-0.171-0.646,0l-3.061,3.064H2.019c-0.251,0-0.457,0.205-0.457,0.456v9.578c0,0.251,0.206,0.456,0.457,0.456h13.683c0.252,0,0.457-0.205,0.457-0.456V7.533l2.144-2.146C18.481,5.208,18.483,4.917,18.303,4.742 M15.258,15.929H2.476V7.263h9.754L9.695,9.792c-0.057,0.057-0.101,0.13-0.119,0.212L9.18,11.36h-3.98c-0.251,0-0.457,0.205-0.457,0.456c0,0.253,0.205,0.456,0.457,0.456h4.336c0.023,0,0.899,0.02,1.498-0.127c0.312-0.077,0.55-0.137,0.55-0.137c0.08-0.018,0.155-0.059,0.212-0.118l3.463-3.443V15.929z M11.241,11.156l-1.078,0.267l0.267-1.076l6.097-6.091l0.808,0.808L11.241,11.156z" />
</SvgIcon>
</IconButton>
<IconButton aria-label="TT">
<SvgIcon>
<path d="M12.075,10.812c1.358-0.853,2.242-2.507,2.242-4.037c0-2.181-1.795-4.618-4.198-4.618S5.921,4.594,5.921,6.775c0,1.53,0.884,3.185,2.242,4.037c-3.222,0.865-5.6,3.807-5.6,7.298c0,0.23,0.189,0.42,0.42,0.42h14.273c0.23,0,0.42-0.189,0.42-0.42C17.676,14.619,15.297,11.677,12.075,10.812 M6.761,6.775c0-2.162,1.773-3.778,3.358-3.778s3.359,1.616,3.359,3.778c0,2.162-1.774,3.778-3.359,3.778S6.761,8.937,6.761,6.775 M3.415,17.69c0.218-3.51,3.142-6.297,6.704-6.297c3.562,0,6.486,2.787,6.705,6.297H3.415z" />
</SvgIcon>
</IconButton>
<IconButton aria-label="TT">
<SvgIcon>
<path d="M15.684,16.959L10.879,8.52c0.886-0.343,1.517-1.193,1.517-2.186c0-1.296-1.076-2.323-2.396-2.323S7.604,5.037,7.604,6.333c0,0.993,0.63,1.843,1.517,2.186l-4.818,8.439c-0.189,0.311,0.038,0.708,0.412,0.708h10.558C15.645,17.667,15.871,17.27,15.684,16.959 M8.562,6.333c0-0.778,0.645-1.382,1.438-1.382s1.438,0.604,1.438,1.382c0,0.779-0.645,1.412-1.438,1.412S8.562,7.113,8.562,6.333 M5.55,16.726L10,8.91l4.435,7.815H5.55z M15.285,9.62c1.26-2.046,1.26-4.525,0-6.572c-0.138-0.223-0.064-0.512,0.162-0.646c0.227-0.134,0.521-0.063,0.658,0.16c1.443,2.346,1.443,5.2,0,7.546c-0.236,0.382-0.641,0.17-0.658,0.159C15.221,10.131,15.147,9.842,15.285,9.62 M13.395,8.008c0.475-1.063,0.475-2.286,0-3.349c-0.106-0.238,0.004-0.515,0.246-0.62c0.242-0.104,0.525,0.004,0.632,0.242c0.583,1.305,0.583,2.801,0,4.106c-0.214,0.479-0.747,0.192-0.632,0.242C13.398,8.523,13.288,8.247,13.395,8.008 M3.895,10.107c-1.444-2.346-1.444-5.2,0-7.546c0.137-0.223,0.431-0.294,0.658-0.16c0.226,0.135,0.299,0.424,0.162,0.646c-1.26,2.047-1.26,4.525,0,6.572c0.137,0.223,0.064,0.512-0.162,0.646C4.535,10.277,4.131,10.489,3.895,10.107 M5.728,8.387c-0.583-1.305-0.583-2.801,0-4.106c0.106-0.238,0.39-0.346,0.631-0.242c0.242,0.105,0.353,0.382,0.247,0.62c-0.475,1.063-0.475,2.286,0,3.349c0.106,0.238-0.004,0.515-0.247,0.62c-0.062,0.027-0.128,0.04-0.192,0.04C5.982,8.668,5.807,8.563,5.728,8.387" />
</SvgIcon>
</IconButton>
<IconButton aria-label="TT">
<SvgIcon>
<path d="M6.176,7.241V6.78c0-0.221-0.181-0.402-0.402-0.402c-0.221,0-0.403,0.181-0.403,0.402v0.461C4.79,7.416,4.365,7.955,4.365,8.591c0,0.636,0.424,1.175,1.006,1.35v3.278c0,0.222,0.182,0.402,0.403,0.402c0.222,0,0.402-0.181,0.402-0.402V9.941c0.582-0.175,1.006-0.714,1.006-1.35C7.183,7.955,6.758,7.416,6.176,7.241 M5.774,9.195c-0.332,0-0.604-0.272-0.604-0.604c0-0.332,0.272-0.604,0.604-0.604c0.332,0,0.604,0.272,0.604,0.604C6.377,8.923,6.105,9.195,5.774,9.195 M10.402,10.058V6.78c0-0.221-0.181-0.402-0.402-0.402c-0.222,0-0.402,0.181-0.402,0.402v3.278c-0.582,0.175-1.006,0.714-1.006,1.35c0,0.637,0.424,1.175,1.006,1.351v0.461c0,0.222,0.181,0.402,0.402,0.402c0.221,0,0.402-0.181,0.402-0.402v-0.461c0.582-0.176,1.006-0.714,1.006-1.351C11.408,10.772,10.984,10.233,10.402,10.058M10,12.013c-0.333,0-0.604-0.272-0.604-0.604S9.667,10.805,10,10.805c0.332,0,0.604,0.271,0.604,0.604S10.332,12.013,10,12.013M14.629,8.448V6.78c0-0.221-0.182-0.402-0.403-0.402c-0.221,0-0.402,0.181-0.402,0.402v1.668c-0.581,0.175-1.006,0.714-1.006,1.35c0,0.636,0.425,1.176,1.006,1.351v2.07c0,0.222,0.182,0.402,0.402,0.402c0.222,0,0.403-0.181,0.403-0.402v-2.07c0.581-0.175,1.006-0.715,1.006-1.351C15.635,9.163,15.21,8.624,14.629,8.448 M14.226,10.402c-0.331,0-0.604-0.272-0.604-0.604c0-0.332,0.272-0.604,0.604-0.604c0.332,0,0.604,0.272,0.604,0.604C14.83,10.13,14.558,10.402,14.226,10.402 M17.647,3.962H2.353c-0.221,0-0.402,0.181-0.402,0.402v11.27c0,0.222,0.181,0.402,0.402,0.402h15.295c0.222,0,0.402-0.181,0.402-0.402V4.365C18.05,4.144,17.869,3.962,17.647,3.962 M17.245,15.232H2.755V4.768h14.49V15.232z" />
</SvgIcon>
</IconButton>
</div>
</Toolbar>
</AppBar>
</div>
);
}
}
BottomToolBar.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(BottomToolBar);
+106 -9
View File
@@ -1,7 +1,9 @@
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 CardContent from '@material-ui/core/CardContent';
import CardHeader from '@material-ui/core/CardHeader';
@@ -9,23 +11,81 @@ import CardMedia from '@material-ui/core/CardMedia';
import Typography from '@material-ui/core/Typography';
const { publicRuntimeConfig } = getConfig()
const styles = theme => ({
card: {
display: 'flex',
position: 'relative',
height: '50vh',
width: '100%',
[theme.breakpoints.up('md')]: {
width : '30%',
},
[theme.breakpoints.down('md')]: {
width : '40%',
},
[theme.breakpoints.down('xs')]: {
width : '100%',
},
margin: '1vh 2vh 1vh 2vh',
[theme.breakpoints.up('sm')]: {
margin: '1vh 0 1vh 0',
},
borderRadius: 0
},
details: {
details_container: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: '8vh 0 0 0',
},
company_title: {
fontSize: '1em',
fontWeight: 'normal',
textTransform: 'uppercase',
},
content: {
flex: '1 0 auto',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
flexWrap: 'wrap',
width: '100%',
padding: 0,
},
cover: {
width: 151,
height: 151,
width: '100%',
height: '50%',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
},
logo_container: {
display: 'flex',
alignItems: 'center',
width: 100,
height: 100,
position: 'absolute',
left: '50%',
top: '50%',
transform: 'translate(-50%, -66%)',
backgroundColor: 'white',
boxShadow: '0 8px 6px -6px grey',
},
logo: {
width: '100%',
height: 'auto',
objectfit: 'contain',
borderRadius: 0,
},
chip: {
margin: '0 1vh 0 1vh',
}
});
class CompanyRowComponent extends React.Component {
render() {
@@ -34,30 +94,67 @@ class CompanyRowComponent extends React.Component {
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.logoRootUrl + rowData.logo
return (
<Card onClick={() => Router.push(`/Company?id=${rowData.id}`)}>
<CardHeader />
<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>
<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 variant="headline" component="h3"
<Typography gutterBottom component="h3"
className={classes.details}>
{rowData.brand_name}
</Typography>
<Typography gutterBottom variant="headline" component="h4"
<Typography gutterBottom component="h4"
className={classes.details}>
{rowData.website}
</Typography>
<Typography gutterBottom variant="headline" component="h5"
<Typography gutterBottom component="h5"
className={classes.details}>
{rowData.description}
</Typography>
</CardContent>
</CardContent> */}
</Card>
);
}
@@ -1,94 +0,0 @@
import React 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 Input from '@material-ui/core/Input';
import Badge from '@material-ui/core/Badge';
import MenuItem from '@material-ui/core/MenuItem';
import Menu from '@material-ui/core/Menu';
import { fade } from '@material-ui/core/styles/colorManipulator';
import { withStyles } from '@material-ui/core/styles';
import SearchIcon from '@material-ui/icons/Search';
import AccountCircle from '@material-ui/icons/AccountCircle';
import MailIcon from '@material-ui/icons/Mail';
import NotificationsIcon from '@material-ui/icons/Notifications';
import MoreIcon from '@material-ui/icons/MoreVert';
import SvgIcon from '@material-ui/core/SvgIcon';
import Router from 'next/router'
const styles = theme => ({
root: {
width: '100%',
},
grow: {
flexGrow: 1,
},
logo: {
width: '48px',
height: '48px'
},
sectionMobile: {
display: 'flex',
},
});
class PrimarySearchAppBar extends React.Component {
state = {
anchorEl: null,
mobileMoreAnchorEl: null,
};
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<AppBar position="fixed">
<Toolbar>
{
this.props.backLink != "" ?
<IconButton className={classes.menuButton} color="inherit" aria-label="Back" onClick={() => Router.push(this.props.backLink)}>
<SvgIcon>
<path d="M11.739,13.962c-0.087,0.086-0.199,0.131-0.312,0.131c-0.112,0-0.226-0.045-0.312-0.131l-3.738-3.736c-0.173-0.173-0.173-0.454,0-0.626l3.559-3.562c0.173-0.175,0.454-0.173,0.626,0c0.173,0.172,0.173,0.451,0,0.624l-3.248,3.25l3.425,3.426C11.911,13.511,11.911,13.789,11.739,13.962 M18.406,10c0,4.644-3.763,8.406-8.406,8.406S1.594,14.644,1.594,10S5.356,1.594,10,1.594S18.406,5.356,18.406,10 M17.521,10c0-4.148-3.373-7.521-7.521-7.521c-4.148,0-7.521,3.374-7.521,7.521c0,4.148,3.374,7.521,7.521,7.521C14.147,17.521,17.521,14.148,17.521,10"></path>
</SvgIcon>
</IconButton>
:
<IconButton className={classes.menuButton} color="inherit" aria-label="Open drawer" onClick={() => Router.push('/')}>
<SvgIcon>
<path d="M20 12l-1.41-1.41L13 5.17V4h-2v12.17l-5.58-5.59L1 12l8 8 8-8z" />
</SvgIcon>
</IconButton>
}
<div className={classes.logo}>
<img src={this.props.logo} />
</div>
<div className={classes.grow} />
<div className={classes.sectionMobile}>
<IconButton color="inherit">
<Badge className={classes.margin} badgeContent={42} color="secondary">
<NotificationsIcon />
</Badge>
</IconButton>
</div>
</Toolbar>
</AppBar>
</div>
);
}
}
PrimarySearchAppBar.propTypes = {
classes: PropTypes.object.isRequired,
backLink: PropTypes.string,
logo: PropTypes.string,
};
export default withStyles(styles)(PrimarySearchAppBar);
+7 -4
View File
@@ -1,6 +1,7 @@
import Link from 'next/link'
import { withStyles } from '@material-ui/core/styles'
import BottomToolbar from './BottomToolbar';
import { Fragment, Children } from 'react';
import { Button } from '@material-ui/core';
const styles = theme => ({
root: {
@@ -9,11 +10,13 @@ const styles = theme => ({
},
});
function Footer(props) {
function Footer(props) {
const { classes } = props;
return (
<BottomToolbar/>
<Fragment>
{props.children}
</Fragment>
);
}
+305 -16
View File
@@ -1,26 +1,315 @@
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 PropTypes from "prop-types";
import { withStyles } from '@material-ui/core/styles'
import PSAB from './PrimarySearchAppBar'
import Drawer from '@material-ui/core/Drawer';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import Divider from '@material-ui/core/Divider';
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 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';
const styles = theme => ({
root: {
position: 'relative',
height: '10vh'
root: {
width: '100%',
'& a': {
textDecoration: 'none'
}
},
grow: {
flexGrow: 1,
},
bar: {
},
menuButton: {
marginLeft: -12,
marginRight: 20,
display: 'block'
},
menuLogo: {
cursor: 'pointer',
[theme.breakpoints.down('md')]: {
width:'200px'
},
[theme.breakpoints.down('sm')]: {
width:'100px'
},
},
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')]: {
display: 'flex',
},
},
sectionMobile: {
display: 'flex',
[theme.breakpoints.up('md')]: {
display: 'none',
},
},
fullList: {
width: 'auto',
cursor: 'pointer'
},
});
function Header(props) {
return (
<PSAB backLink={props.backLink}/>
);
class Header extends React.Component {
state = {
top: false,
left: false,
bottom: false,
right: false,
toggle: true
};
componentDidMount() {
}
toggleDrawer = (side, open) => () => {
this.setState({
[side]: open,
});
};
toggle = () => this.setState(state => ({ toggle: !state.toggle }))
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<Drawer anchor="left" open={this.state.left} onClose={this.toggleDrawer('left', false)}>
<div
tabIndex={0}
role="button"
onClick={this.toggleDrawer('left', false)}
onKeyDown={this.toggleDrawer('left', false)}
>
<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 />
<Link href="/" prefetch >
<a><ListItem>
<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>
<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 &&
(<div className="alert alert-info"><CircularProgress color="secondary" />Chargement...</div>
)}
{!!!this.props.loading && !!!this.props.fetched
&&
<div className={classes.fullList}>
<List>
<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>
<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} />
<img alt="talents-tube" src='/static/images/logos/Logo-header.svg' className={classes.menuLogo} />
<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.defaultProps = {
backLink : ""
}
Header.propTypes = {
backLink : PropTypes.string
classes: PropTypes.object.isRequired,
};
function mapStateToProps(state) {
return {
user: state.user,
fetched: !!state.user.fetched,
loading: !!state.user.loading
};
}
export default withStyles(styles)(Header)
export default withStyles(styles)(connect(mapStateToProps, { fetchCurrentUserRequest, requestLogout })(Header));
@@ -0,0 +1,68 @@
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 Tile from './Tile';
const styles = theme => ({
root: {
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'space-around',
overflow: 'hidden',
backgroundColor: theme.palette.background.paper,
},
gridList: {
flexWrap: 'nowrap',
// Promote the list into his own layer on Chrome. This cost memory but helps keeping high FPS.
transform: 'translateZ(0)',
height: '100%',
},
gridListTile: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
height: '100% !important',
'&:first-child': {
marginLeft: '3vw',
},
},
rootGridListTile: {
margin: '3vw',
},
tile: {
width: '100% !important',
overflow: 'visible !important',
},
});
class HorizontalScroller extends Component {
render() {
const { classes } = this.props
const children =(tile)=> React.Children.map(this.props.children, child => {
return React.cloneElement(child, {
tile
});
});
return (
<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>
</div>
)
}
}
export default withStyles(styles)(HorizontalScroller)
@@ -0,0 +1,34 @@
import React, { Component } from 'react'
import { Typography, Button } from '@material-ui/core';
import { withStyles } from '@material-ui/core/styles';
import TextField from '@material-ui/core/TextField';
const styles = theme => ({
textField: {
textAlign: 'center',
justifyContent: 'center',
},
})
class NewsLetterRegistration extends Component {
render() {
let {classes} = this.props
return (
<div>
<Typography gutterBottom component="h3">
Recevez les dernières nouvelles de Talents Tube par e-mail
</Typography>
<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>
)
}
}
export default withStyles(styles)(NewsLetterRegistration)
+8 -12
View File
@@ -10,7 +10,7 @@ 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 { Button } from '@material-ui/core';
const styles = theme => ({
card: {
@@ -39,7 +39,7 @@ const styles = theme => ({
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: '8vh 0 0 0',
padding: '10vh 0 0 0',
},
company_title: {
fontSize: '1em',
@@ -78,9 +78,6 @@ const styles = theme => ({
objectfit: 'contain',
borderRadius: 0,
},
chip: {
margin: '0 1vh 0 1vh',
}
});
@@ -89,14 +86,13 @@ class OffreRowComponent extends React.Component {
render() {
const { classes, theme, rowData } = this.props;
const { classes, rowData } = this.props;
const imgDefaultUrl = "https://www.talentstube.com/img/default_picture_company.svg"
const imgUrl = (rowData.video.thumbnails[0] && rowData.video.thumbnails[0].sizes[4]) ? rowData.video.thumbnails[0].sizes[4].link : imgDefaultUrl
const logoUrl = publicRuntimeConfig.logoUrl + rowData.company.logo
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 (
<Card className={classes.card} onClick={() => Router.push(`/Offre?id=${rowData.id}`)}>
<CardContent className={classes.content}>
<CardMedia
@@ -114,7 +110,7 @@ class OffreRowComponent extends React.Component {
gutterBottom
variant="headline"
variant="h6"
component="h4"
component="h3"
align="center"
className={classes.company_title}>
{rowData.company.business_name}
@@ -123,7 +119,7 @@ class OffreRowComponent extends React.Component {
gutterBottom
variant="headline"
variant="h6"
component="h3"
component="h4"
align="center"
className={classes.job_title}>
{rowData.title}
@@ -0,0 +1,164 @@
import React, { Component, Fragment } from 'react';
import Button from '@material-ui/core/Button';
import Card from '@material-ui/core/Card';
import CardActionArea from '@material-ui/core/CardActionArea';
import CardActions from '@material-ui/core/CardActions';
import CardContent from '@material-ui/core/CardContent';
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';
const styles = theme => ({
cardSnack: {
maxWidth: 345,
},
media: {
height: 140,
}
});
class PWAInstallSnack extends Component {
state = {
openSnack: false,
buttonDisplay: true
}
isAvailable = () =>{
console.log(this.buttonDisplay)
return this.state.buttonDisplay;
}
initInstall = () =>
{
this.setState({openSnack: true})
}
getStateAndHelpers() {
return {
on: this.state.openSnack,
initInstall: this.initInstall,
}
}
iOS() {
var iDevices = [
'iPad Simulator',
'iPhone Simulator',
'iPod Simulator',
'iPad',
'iPhone',
'iPod'
];
if (!!navigator.platform) {
while (iDevices.length) {
if (navigator.platform === iDevices.pop()){ return true; }
}
}
return false;
}
componentDidMount() {
if (window !== undefined) {
// don't show if we are in App
if (window.navigator.standalone ||
window.matchMedia('(display-mode: standalone)').matches)
{
console.log('standalone')
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 })
}
}
}
//A2HS 'Add 2 Home Screen'
PromptA2HS = (event, reason) => {
this.setState({ openSnack: false })
console.log('prompted')
if (window !== undefined) {
window.promptInstall();
}
}
IsSafari = () => {
if (typeof window !== 'undefined') {
var isSafari = /Safari/.test(window.navigator.userAgent) && /Apple Computer/.test(window.navigator.vendor);
return isSafari;
} else
return false;
}
handleClose = () => {
this.setState({ openSnack: false });
}
render() {
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 variant="h5" component="h2">
-> les PWA doivent encore s'installer manuellement sous IOS
</Typography>
</CardContent>
<CardActions>
<Button name="compris" size="small" color="secondary" onClick={this.handleClose}>
j'ai compris
</Button>
</CardActions>
</CardActionArea>
</Card>);
var usualSnack = (<Card className={classes.cardSnack}>
<CardActionArea>
<CardContent>
<Typography gutterBottom variant="h5" component="h2">
Voulez-vous installer notre application ?
</Typography>
</CardContent>
</CardActionArea>
<CardActions>
<Button name='oui' size="small" color="secondary" onClick={this.PromptA2HS}>
oui
</Button>
<Button name='non' size="small" color="secondary" onClick={this.handleClose}>
non
</Button>
</CardActions>
</Card>);
return <Fragment>
<Snackbar
anchorOrigin={{ vertical: 'top', horizontal: 'right' }}
open={this.state.openSnack}
onClose={this.handleClose}
ContentProps={{
'aria-describedby': 'message-id',
}}>
{this.IsSafari() ? safariSnack : usualSnack}
</Snackbar>
{this.state.buttonDisplay && this.props.children(this.getStateAndHelpers())}
</Fragment>
}
}
export default withStyles(styles)(PWAInstallSnack)
@@ -1,140 +0,0 @@
import React 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 Input from '@material-ui/core/Input';
import Badge from '@material-ui/core/Badge';
import MenuItem from '@material-ui/core/MenuItem';
import Menu from '@material-ui/core/Menu';
import { fade } from '@material-ui/core/styles/colorManipulator';
import { withStyles } from '@material-ui/core/styles';
import SearchIcon from '@material-ui/icons/Search';
import AccountCircle from '@material-ui/icons/AccountCircle';
import MailIcon from '@material-ui/icons/Mail';
import NotificationsIcon from '@material-ui/icons/Notifications';
import MoreIcon from '@material-ui/icons/MoreVert';
import SvgIcon from '@material-ui/core/SvgIcon';
import Router from 'next/router'
const styles = theme => ({
root: {
width: '100%',
},
grow: {
flexGrow: 1,
},
search: {
position: 'relative',
borderRadius: theme.shape.borderRadius,
backgroundColor: fade(theme.palette.common.white, 0.15),
'&:hover': {
backgroundColor: fade(theme.palette.common.white, 0.25),
},
marginRight: theme.spacing.unit * 2,
marginLeft: 0,
width: '100%',
[theme.breakpoints.up('sm')]: {
marginLeft: theme.spacing.unit * 3,
width: 'auto',
},
},
searchIcon: {
width: theme.spacing.unit * 9,
height: '100%',
position: 'absolute',
pointerEvents: 'none',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
},
inputRoot: {
color: 'inherit',
width: '100%',
},
inputInput: {
paddingTop: theme.spacing.unit,
paddingRight: theme.spacing.unit,
paddingBottom: theme.spacing.unit,
paddingLeft: theme.spacing.unit,
transition: theme.transitions.create('width'),
width: '100%',
[theme.breakpoints.up('md')]: {
width: 500,
},
},
sectionDesktop: {
display: 'flex',
},
sectionMobile: {
display: 'flex',
},
});
class PrimarySearchAppBar extends React.Component {
state = {
anchorEl: null,
mobileMoreAnchorEl: null,
};
render() {
const { classes } = this.props;
return (
<div className={classes.root}>
<AppBar position="fixed">
<Toolbar>
{
this.props.backLink != "" ?
<IconButton className={classes.menuButton} color="inherit" aria-label="Back" onClick={() => Router.push(this.props.backLink)}>
<SvgIcon>
<path d="M11.739,13.962c-0.087,0.086-0.199,0.131-0.312,0.131c-0.112,0-0.226-0.045-0.312-0.131l-3.738-3.736c-0.173-0.173-0.173-0.454,0-0.626l3.559-3.562c0.173-0.175,0.454-0.173,0.626,0c0.173,0.172,0.173,0.451,0,0.624l-3.248,3.25l3.425,3.426C11.911,13.511,11.911,13.789,11.739,13.962 M18.406,10c0,4.644-3.763,8.406-8.406,8.406S1.594,14.644,1.594,10S5.356,1.594,10,1.594S18.406,5.356,18.406,10 M17.521,10c0-4.148-3.373-7.521-7.521-7.521c-4.148,0-7.521,3.374-7.521,7.521c0,4.148,3.374,7.521,7.521,7.521C14.147,17.521,17.521,14.148,17.521,10"></path>
</SvgIcon>
</IconButton>
:
<IconButton className={classes.menuButton} color="inherit" aria-label="Open drawer" onClick={() => Router.push('/')}>
<SvgIcon>
<path d="M20 12l-1.41-1.41L13 5.17V4h-2v12.17l-5.58-5.59L1 12l8 8 8-8z" />
</SvgIcon>
</IconButton>
}
<div className={classes.search}>
<Input
placeholder="Recherche…"
disableUnderline
classes={{
root: classes.inputRoot,
input: classes.inputInput,
}}
/>
</div>
<div className={classes.grow} />
<div className={classes.sectionMobile}>
<IconButton color="inherit">
<Badge className={classes.margin} badgeContent={42} color="secondary">
<NotificationsIcon />
</Badge>
</IconButton>
</div>
</Toolbar>
</AppBar>
</div>
);
}
}
PrimarySearchAppBar.propTypes = {
classes: PropTypes.object.isRequired,
backLink: PropTypes.string,
};
export default withStyles(styles)(PrimarySearchAppBar);
+119
View File
@@ -0,0 +1,119 @@
import React, { Component } from 'react'
import videojs from 'video.js';
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';
dynamic(() => import('webrtc-adapter'), {
ssr: false
})
const RTCRecorder = dynamic(() => import('RecordRTC'), {
ssr: false
})
const styles = theme => ({
root: {
margin: theme.spacing.unit,
maxWidth: '400px', [theme.breakpoints.down('md')]: {
maxWidth: `${100 - (theme.spacing.unit)}vw`
},
button: {
margin: theme.spacing.unit,
alignSelf: 'flex-end'
},
}
})
class Recorder extends Component {
async componentDidMount() {
var record = (await import('videojs-record')).default
// instantiate Video.js
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);
});
// device is ready
this.player.on('deviceReady', () => {
console.log('device is ready!');
});
// user clicked the record button and started recording
this.player.on('startRecord', () => {
console.log('started recording!');
});
// user completed recording and stream is available
this.player.on('finishRecord', () => {
// 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);
});
// error handling
this.player.on('error', (element, error) => {
console.warn(error);
});
this.player.on('deviceError', () => {
console.error('device error:', this.player.deviceErrorCode);
});
}
// destroy player on unmount
componentWillUnmount() {
if (this.player) {
this.player.dispose();
}
}
sendBlob = () => {
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
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')
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))
console.log('end send Blob')
}
render() {
const { classes } = this.props;
return (
<div>
<div data-vjs-player>
<video id="myVideo" ref={node => this.videoNode = node} className="video-js vjs-default-skin" playsInline></video>
</div>
<div>
<Button type="submit" variant="outlined" color="secondary"
className={classes.button}
onClick={this.sendBlob}>
Send
</Button>
</div>
</div>
);
}
}
export default withStyles(styles)(Recorder)
+233
View File
@@ -0,0 +1,233 @@
import React, {Fragment} from 'react';
import { connect } from "react-redux";
import Validator from "validator";
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"
const styles = theme => ({
container: {
display: 'flex',
flexDirection: 'column',
height: '100%',
},
textField: {
width: '100%'
},
form: {
display: 'flex',
flexDirection: 'column',
},
input50: {
width: '50%',
},
checkboxError:{
color:'red'
}
});
class Register extends React.Component {
state = {
data: {
firstname: '',
lastname: '',
email: '',
password: '',
checkNewsletter: false,
checkCGU: false,
},
errors: {},
loading: false,
showPassword:false
}
validate = data => {
const errors = {};
if (!Validator.isEmail(data.email)) errors.email = "Email invalide";
if (!!!data.password) errors.password = "Requis";
if (!!!data.firstname) errors.firstname = "Requis";
if (!!!data.lastname) errors.lastname = "Requis";
if (!data.checkCGU) errors.checkCGU = "Requis";
return errors;
};
onRegister = e => {
e.preventDefault();
const errors = this.validate(this.state.data);
console.log('onSubmit')
console.log(errors)
this.setState({ errors: errors });
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 })
}
};
componentWillReceiveProps(nextProps) {
this.setState({
errors: nextProps.errors,
loading: nextProps.loading
})
}
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 }});
};
handleChangePasswordVisibility = prop => event => {
this.setState({ [prop]: event.target.value });
};
handleClickShowPassword = () => {
this.setState({ showPassword: !this.state.showPassword });
};
render() {
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}>
<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}
onChange={this.onChange}
id="emailRegister"
name="email"
label="Email"
margin="normal"
type="email"
required
error={!!errors.email}
autoComplete="username email"
/>
<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 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 value={data.checkNewsletter}
onChange={this.handleCheckBoxChange('checkNewsletter')}
/>
}
label="Je souhaite recevoir la newsletter de Talents Tube"
/>
<FormControlLabel
name="checkCGU"
className={!!errors.checkCGU&&classes.checkboxError}
control={
<Checkbox
error={!!errors.checkCGU }
value={data.checkCGU}
onChange={this.handleCheckBoxChange('checkCGU')}
/>
}
label="Je déclare avoir pris connaissance et accepte les termes et les CGU*"
required
/>
<Button type="submit" variant="outlined" color="primary" onClick={this.onRegister}>
S'inscrire
</Button>
<Typography
paragraph={true}
align="center"
>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"} className={classes.link}>
Se connecter
</Link>
</Typography>
</div>
</div>
);
}
}
function mapStateToProps(state) {
return {
loading: !!state.user.loading,
errors: state.user.errors
};
}
export default withStyles(styles)(connect(mapStateToProps, { registerUserRequest, subscribeToNewsletterRequest })(Register));
@@ -0,0 +1,128 @@
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';
const styles = theme => ({
root: {
position: 'relative',
textAlign: 'center',
paddingTop: theme.spacing(20),
justifyContent: 'center',
},
container: {
display: 'flex',
flexDirection: 'column',
position: 'relative',
},
video: {
display: 'flex',
flexDirection: 'column',
},
text: {
position: 'absolute',
},
plyr: {
'.plyr--video .plyr__controls': {
background: null
}
}
});
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) {
super(props);
this.plyrRef = null;
this.setPlyrRef = element => {
this.plyrRef = element;
};
}
state = {
i: 0,
startDate: Date.now()
}
componentDidMount() {
this.timer = setInterval(this.tick.bind(this), 500);
}
componentWillUnmount() {
clearInterval(this.timer);
}
tick() {
// console.log(this.state)
if (new Date() - this.state.startDate >= 8000) {
if (this.state.i == 2)
this.setState({ i: 0, startDate: Date.now() })
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;
}
}
}
render() {
let { classes } = this.props;
let videoId = videoList[0].vimeoId;
// console.log(videoId)
return (
<div className={classes.video}>
{/* 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.text}>
{videoList[this.state.i].adTitle}
</Typography>
<Button variant="outlined">
Voir l'offre
</Button>
</div>
)
}
}
export default withStyles(styles)(ShortVideoHooker);
+125
View File
@@ -0,0 +1,125 @@
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';
const styles = theme => ({
card: {
display: 'flex',
position: 'relative',
height: '60vh',
width: '100%',
[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',
},
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: '50%',
backgroundSize: 'cover',
backgroundRepeat: 'no-repeat',
},
logo_container: {
display: 'flex',
alignItems: 'center',
width: 70,
height: 70,
position: 'absolute',
left: '50%',
top: '50%',
transform: 'translate(-50%, -66%)',
backgroundColor: 'white',
boxShadow: '0 8px 6px -6px grey',
border: 'solid 5px white',
borderRadius: '0.5em',
},
logo: {
width: '100%',
height: 'auto',
objectfit: 'contain',
},
chip: {
margin: '0 1vh 0 1vh',
}
});
const { publicRuntimeConfig } = getConfig()
class Tile extends React.Component {
render() {
const { classes, rowData, children } = 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 (
<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>
);
}
}
Tile.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
rowData: PropTypes.object.isRequired
};
export default withStyles(styles, { withTheme: true })(Tile);
@@ -0,0 +1,71 @@
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';
const styles = theme => ({
details_container: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: '8vh 0 0 0',
},
company_title: {
fontSize: '1em',
fontWeight: 'normal',
textTransform: 'uppercase',
},
chip: {
margin: '0 1vh 0 1vh',
}
});
class TileCompany extends React.Component {
render() {
const { classes, tile } = this.props;
return (
<Fragment>
<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.job_title}>
{tile.title}
</Typography>
</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>
);
}
}
TileCompany.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
tile: PropTypes.object.isRequired
};
export default withStyles(styles, { withTheme: true })(TileCompany);
+78
View File
@@ -0,0 +1,78 @@
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 => ({
details_container: {
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
padding: '8vh 0 0 0',
},
company_title: {
fontSize: '0.8em',
fontWeight: 'normal',
},
job_title: {
fontSize: '1em',
marginLeft: theme.spacing(1),
marginRight: theme.spacing(1),
},
chip: {
margin: '0 1vh 0 1vh',
}
});
class TileOffre extends React.Component {
render() {
const { classes, tile } = this.props;
return (
<Fragment>
<section 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.job_title}>
{tile.title}
</Typography>
</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>
);
}
}
TileOffre.propTypes = {
classes: PropTypes.object.isRequired,
theme: PropTypes.object.isRequired,
tile: PropTypes.object.isRequired
};
export default withStyles(styles, { withTheme: true })(TileOffre);
+4 -1
View File
@@ -1,6 +1,7 @@
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: {
@@ -12,7 +13,9 @@ const styles = theme => ({
function Footer(props) {
const { classes } = props;
return (
<BottomToolbar/>
<Fragment>
</Fragment>
);
+42 -32
View File
@@ -1,12 +1,14 @@
import Griddle from "griddle-react";
import Griddle, { utils } from "griddle-react";
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from "react-redux";
import fetch from 'isomorphic-unfetch'
import api from '../../data/api'
import OffreRow from "../organisms/OffreRow"
import GriddleCustomTable from "../organisms/GriddleCustomTableComponent";
//insights
//
//https://codesandbox.io/s/pw9zy43v1m?module=%2FGrid.js
const CustomTableBody = ({ rowIds, Row, style, className }) => (
@@ -28,73 +30,80 @@ class Grid extends Component {
};
async componentDidMount() {
try {
let data = await api.ads.fetchAds(10);
this.setState({ data });
} catch (error) {
console.log(error);
}
this.props.dataFetcher(
{
offset: this.state.currentPage,
limit: this.state.pageSize
}
);
}
componentWillReceiveProps(nextProps) {
//this.setState({ data: nextProps.games });
// this.setState({ currentPage: nextProps.currentPage });
// this.setState({ recordCount: nextProps.recordCount });
this.setState({ data: nextProps.data });
this.setState({ currentPage: nextProps.currentPage });
this.setState({ recordCount: nextProps.recordCount });
}
_onNext = () => {
const { currentPage, pageSize, filterText } = this.state;
//this.props.fetchUserGamesRequest(currentPage + 1, pageSize, filterText);
console.debug(`-- _onNext -- ${0} -- ${1} -- ${2} --`, currentPage, pageSize, filterText)
this.props.dataFetcher({ offset: currentPage * pageSize, limit: pageSize, keyword: filterText })
};
_onPrevious = () => {
const { currentPage, pageSize, filterText } = this.state;
//this.props.fetchUserGamesRequest(currentPage - 1, pageSize, filterText);
this.props.dataFetcher({ offset: (currentPage - 2) * pageSize + 1, limit: pageSize, keyword: filterText });
};
_onGetPage = pageNumber => {
const { pageSize, filterText } = this.state;
// this.props.fetchUserGamesRequest(pageNumber, pageSize, filterText);
this.props.dataFetcher({ offset: (pageNumber - 1) * pageSize + 1, limit: pageSize, keyword: filterText });
};
_onFilter = filterText => {
this.setState({ currentPage: 1 });
const { currentPage, pageSize } = this.state;
this.setState({ filterText });
//this.props.fetchUserGamesRequest(currentPage, pageSize, filterText);
this.props.dataFetcher({ offset: (currentPage - 1) * pageSize + 1, limit: pageSize, keyword: filterText });
};
render() {
const style = {
styles: {
TableBody: { display: "flex", flexWrap: "wrap", justifyContent: "space-around"},
TableBody: { display: "flex", flexWrap: "wrap", justifyContent: "space-around" },
}
}
}
const { data, currentPage, pageSize, recordCount } = this.state;
// console.debug("-- render -- ")
// console.debug(data)
const NewLayout = ({ Table, Pagination, Filter }) => (
<div>
<Filter />
<Pagination />
<Table />
</div>
);
const rowDataSelector = (state, { griddleKey }) =>
state
const rowDataSelector = (state, { griddleKey }) => {
// console.debug("rowDataSelector")
// console.debug(state)
return state
.get("data")
.find(rowMap => rowMap.get("griddleKey") === griddleKey)
.toJSON();
.toJSON()
}
const enhancedWithRowData = connect((state, props) => ({
const enhancedWithRowData = utils.connect((state, props) => ({
// rowData will be available into MyCustomComponent
rowData: rowDataSelector(state, props),
}));
return (
<div>
<Griddle
data={data}
@@ -105,15 +114,15 @@ class Grid extends Component {
}}
components={{
Layout: NewLayout,
Row: enhancedWithRowData(this.props.CustomRowComponent),
Row: this.props.CustomRowComponent,
TableContainer: GriddleCustomTable,
TableBody: CustomTableBody
}}
events={{
// onNext: this._onNext,
// onPrevious: this._onPrevious,
// onGetPage: this._onGetPage,
// onFilter: this._onFilter
onNext: this._onNext,
onPrevious: this._onPrevious,
onGetPage: this._onGetPage,
onFilter: this._onFilter
}}
styleConfig={style}
/>
@@ -124,8 +133,9 @@ class Grid extends Component {
}
Grid.propTypes = {
//dataFetcher: PropTypes.func.isRequired,
CustomRowComponent: PropTypes.func.isRequired,
dataFetcher: PropTypes.func.isRequired,
CustomRowComponent: PropTypes.any.isRequired,
data: PropTypes.any
}
export default Grid;
-26
View File
@@ -1,26 +0,0 @@
import Link from 'next/link'
import PropTypes from "prop-types";
import { withStyles } from '@material-ui/core/styles'
import PSAB from '../organisms/PrimarySearchAppBar'
const styles = theme => ({
root: {
position: 'relative',
height: '10vh'
},
});
function Header(props) {
return (
<PSAB backLink={props.backLink}/>
);
}
Header.defaultProps = {
backLink : ""
}
Header.propTypes = {
backLink : PropTypes.string
}
export default withStyles(styles)(Header)
+3 -8
View File
@@ -1,6 +1,5 @@
import { withStyles } from '@material-ui/core/styles'
import Header from './Header'
import Footer from './Footer'
import Header from '../organisms/Header'
const styles = theme => ({
root: {
@@ -50,17 +49,13 @@ function Layout(props) {
<div className={classes.root}>
<div id="H" className={classes.head}>
<div className={classes.inner}>
<Header />
<Header searchBar={true}/>
</div>
</div>
<div id="C" className={classes.content}>
{props.children}
</div>
<div id="T" className={classes.foot}>
<div className={classes.inner}>
<Footer />
</div>
</div>
</div>
)
}
@@ -1,63 +0,0 @@
import PropTypes from "prop-types";
import { withStyles } from '@material-ui/core/styles'
import DetailAppBar from '../organisms/DetailAppBar'
const styles = theme => ({
root: {
height: '100%'
},
head: {
width: '100%',
height: '56px',
background: 'silver',
position: 'fixed',
[theme.breakpoints.up('sm')]: {
height: '64px'
}
},
content: {
top: '56px',
height: 'calc(100vh - 56px)',
[theme.breakpoints.up('sm')]: {
top: '64px',
height: 'calc(100vh - 64px)',
},
position: 'relative',
overflow: 'auto',
}
});
function LayoutDetail(props) {
const { classes } = props;
return (
<div className={classes.root}>
<div id="H" className={classes.head}>
<div className={classes.inner}>
<DetailAppBar backLink={props.backLink} logo={props.logo}/>
</div>
</div>
<div id="C" className={classes.content}>
{props.children}
</div>
</div>
)
}
LayoutDetail.defaultProps = {
backLink:"/",
logo: "default.svg"
}
LayoutDetail.propTypes = {
backLink : PropTypes.string,
logo: PropTypes.string,
}
export default withStyles(styles)(LayoutDetail)
+1 -1
View File
@@ -1,7 +1,7 @@
import PropTypes from "prop-types";
import { withStyles } from '@material-ui/core/styles'
import Header from './Header'
import Header from '../organisms/Header'
const styles = theme => ({
root: {
@@ -0,0 +1,81 @@
import { withStyles } from '@material-ui/core/styles'
import Header from '../organisms/Header'
import { Button } from '@material-ui/core';
import Router from 'next/router';
import ButtonBase from "@material-ui/core/ButtonBase";
import ArrowLeft from '@material-ui/icons/keyboardArrowLeft';
const styles = theme => ({
root: {
height: '100%'
},
foot: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
position: 'fixed',
[theme.breakpoints.up('sm')]: {
height: '64px'
},
},
content: {
height: 'calc(100vh - 56px)',
[theme.breakpoints.up('sm')]: {
height: 'calc(100vh - 64px)',
},
position: 'relative',
overflow: 'auto',
},
back:
{
position: 'absolute',
zIndex:10,
color : 'white',
backgroundColor: 'grey',
border: 'none',
color: 'white',
padding: '10px',
textAlign: 'center',
textDecoration: 'none',
display: 'inlineBlock',
fontSize: '38px',
margin:' 10px 16px',
borderRadius: '50%',
}
})
function Layout(props) {
const { classes } = props;
return (
<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>
<div id="F" className={classes.foot}>
{/* <div className={classes.inner}>
<div className={classes.grow} /> */}
<Button variant="outlined" color="secondary" >Postuler</Button>
{/* <div className={classes.grow} />
</div> */}
</div>
</div>
)
}
export default withStyles(styles)(Layout)
-208
View File
@@ -1,208 +0,0 @@
import React from 'react'
import Router from 'next/router'
import Head from 'next/head'
import Link from 'next/link'
import { Container, Row, Col, Nav, NavItem, Button, Form, NavLink, Collapse,
Navbar, NavbarToggler, NavbarBrand, Modal, ModalHeader, ModalBody,
ModalFooter, ListGroup, ListGroupItem } from 'reactstrap'
import Signin from './signin'
import { NextAuth } from 'next-auth/client'
import Cookies from 'universal-cookie'
export default class extends React.Component {
static propTypes() {
return {
session: React.PropTypes.object.isRequired,
providers: React.PropTypes.object.isRequired,
children: React.PropTypes.object.isRequired,
fluid: React.PropTypes.boolean,
navmenu: React.PropTypes.boolean,
signinBtn: React.PropTypes.boolean
}
}
constructor(props) {
super(props)
this.state = {
navOpen: false,
modal: false,
providers: null
}
this.toggleModal = this.toggleModal.bind(this)
}
async toggleModal(e) {
if (e) e.preventDefault()
// Save current URL so user is redirected back here after signing in
if (this.state.modal !== true) {
const cookies = new Cookies()
cookies.set('redirect_url', window.location.pathname, { path: '/' })
}
this.setState({
providers: this.state.providers || await NextAuth.providers(),
modal: !this.state.modal
})
}
render() {
return (
<MainBody navmenu={this.props.navmenu} fluid={this.props.fluid} container={this.props.container}>
{this.props.children}
</MainBody>
)
}
}
export class MainBody extends React.Component {
render() {
if (this.props.container === false) {
return (
<React.Fragment>
{this.props.children}
</React.Fragment>
)
} else if (this.props.navmenu === false) {
return (
<Container fluid={this.props.fluid} style={{marginTop: '1em'}}>
{this.props.children}
</Container>
)
} else {
return (
<Container fluid={this.props.fluid} style={{marginTop: '1em'}}>
<Row>
<Col xs="12" md="9" lg="10">
{this.props.children}
</Col>
<Col xs="12" md="3" lg="2" style={{paddingTop: '1em'}}>
<h5 className="text-muted text-uppercase">Examples</h5>
<ListGroup>
<ListGroupItem>
<Link prefetch href="/examples/authentication"><a href="/examples/authentication" className="d-block">Auth</a></Link>
</ListGroupItem>
<ListGroupItem>
<Link prefetch href="/examples/async"><a href="/examples/async" className="d-block">Async</a></Link>
</ListGroupItem>
<ListGroupItem>
<Link prefetch href="/examples/layout"><a href="/examples/layout" className="d-block">Layout</a></Link>
</ListGroupItem>
<ListGroupItem>
<Link prefetch href="/examples/routing"><a href="/examples/routing" className="d-block">Routing</a></Link>
</ListGroupItem>
<ListGroupItem>
<Link prefetch href="/examples/styling"><a href="/examples/styling" className="d-block">Styling</a></Link>
</ListGroupItem>
</ListGroup>
</Col>
</Row>
</Container>
)
}
}
}
export class UserMenu extends React.Component {
constructor(props) {
super(props)
this.handleSignoutSubmit = this.handleSignoutSubmit.bind(this)
}
async handleSignoutSubmit(event) {
event.preventDefault()
// Save current URL so user is redirected back here after signing out
const cookies = new Cookies()
cookies.set('redirect_url', window.location.pathname, { path: '/' })
await NextAuth.signout()
Router.push('/')
}
render() {
if (this.props.session && this.props.session.user) {
// If signed in display user dropdown menu
const session = this.props.session
return (
<Nav className="ml-auto" navbar>
{/*<!-- Uses .nojs-dropdown CSS to for a dropdown that works without client side JavaScript ->*/}
<div tabIndex="2" className="dropdown nojs-dropdown">
<div className="nav-item">
<span className="dropdown-toggle nav-link d-none d-md-block">
<span className="icon ion-md-contact" style={{fontSize: '2em', position: 'absolute', top: -5, left: -25}}></span>
</span>
<span className="dropdown-toggle nav-link d-block d-md-none">
<span className="icon ion-md-contact mr-2"></span>
{session.user.name || session.user.email}
</span>
</div>
<div className="dropdown-menu">
<Link prefetch href="/account">
<a href="/account" className="dropdown-item"><span className="icon ion-md-person mr-1"></span> Your Account</a>
</Link>
<AdminMenuItem {...this.props}/>
<div className="dropdown-divider d-none d-md-block"/>
<div className="dropdown-item p-0">
<Form id="signout" method="post" action="/auth/signout" onSubmit={this.handleSignoutSubmit}>
<input name="_csrf" type="hidden" value={this.props.session.csrfToken}/>
<Button type="submit" block className="pl-4 rounded-0 text-left dropdown-item"><span className="icon ion-md-log-out mr-1"></span> Sign out</Button>
</Form>
</div>
</div>
</div>
</Nav>
)
} if (this.props.signinBtn === false) {
// If not signed in, don't display sign in button if disabled
return null
} else {
// If not signed in, display sign in button
return (
<Nav className="ml-auto" navbar>
<NavItem>
{/**
* @TODO Add support for passing current URL path as redirect URL
* so that users without JavaScript are also redirected to the page
* they were on before they signed in.
**/}
<a href="/auth?redirect=/" className="btn btn-outline-primary" onClick={this.props.toggleModal}><span className="icon ion-md-log-in mr-1"></span> Sign up / Sign in</a>
</NavItem>
</Nav>
)
}
}
}
export class AdminMenuItem extends React.Component {
render() {
if (this.props.session.user && this.props.session.user.admin === true) {
return (
<React.Fragment>
<Link prefetch href="/admin">
<a href="/admin" className="dropdown-item"><span className="icon ion-md-settings mr-1"></span> Admin</a>
</Link>
</React.Fragment>
)
} else {
return(<div/>)
}
}
}
export class SigninModal extends React.Component {
render() {
if (this.props.providers === null) return null
return (
<Modal isOpen={this.props.modal} toggle={this.props.toggleModal} style={{maxWidth: 700}}>
<ModalHeader>Sign up / Sign in</ModalHeader>
<ModalBody style={{padding: '1em 2em'}}>
<Signin session={this.props.session} providers={this.props.providers}/>
</ModalBody>
</Modal>
)
}
}
-25
View File
@@ -1,25 +0,0 @@
import React from 'react'
import Layout from './layoutAuth'
import { NextAuth } from 'next-auth/client'
export default class extends React.Component {
static async getInitialProps({req}) {
return {
session: await NextAuth.init({req}),// Add this.props.session to all pages
lang: 'en'// Add a lang property for accessibility
}
}
adminAcccessOnly() {
return (
<Layout {...this.props} navmenu={false}>
<div className="text-center pt-5 pb-5">
<h1 className="display-4 mb-5">Access Denied</h1>
<p className="lead">You must be signed in as an administrator to access this page.</p>
</div>
</Layout>
)
}
}
-103
View File
@@ -1,103 +0,0 @@
import React from 'react'
import Router from 'next/router'
import { Row, Col, Form, Input, Label, Button } from 'reactstrap'
import Cookies from 'universal-cookie'
import { NextAuth } from 'next-auth/client'
export default class extends React.Component {
constructor(props) {
super(props)
this.state = {
email: '',
session: this.props.session,
providers: this.props.providers,
submitting: false
}
this.handleSubmit = this.handleSubmit.bind(this)
this.handleEmailChange = this.handleEmailChange.bind(this)
}
handleEmailChange(event) {
this.setState({
email: event.target.value.trim()
})
}
handleSubmit(event) {
event.preventDefault()
if (!this.state.email) return
this.setState({
submitting: true
})
// Save current URL so user is redirected back here after signing in
const cookies = new Cookies()
cookies.set('redirect_url', window.location.pathname, { path: '/' })
NextAuth.signin(this.state.email)
.then(() => {
Router.push(`/auth/check-email?email=${this.state.email}`)
})
.catch(err => {
Router.push(`/auth/error?action=signin&type=email&email=${this.state.email}`)
})
}
render() {
if (this.props.session.user) {
return(<div/>)
} else {
return (
<React.Fragment>
<p className="text-center" style={{marginTop: 10, marginBottom: 30}}>{`If you don't have an account, one will be created when you sign in.`}</p>
<Row>
<Col xs={12} md={6}>
<SignInButtons providers={this.props.providers}/>
</Col>
<Col xs={12} md={6}>
<Form id="signin" method="post" action="/auth/email/signin" onSubmit={this.handleSubmit}>
<Input name="_csrf" type="hidden" value={this.state.session.csrfToken}/>
<p>
<Label htmlFor="email">Email address</Label><br/>
<Input name="email" disabled={this.state.submitting} type="text" placeholder="j.smith@example.com" id="email" className="form-control" value={this.state.email} onChange={this.handleEmailChange}/>
</p>
<p className="text-right">
<Button id="submitButton" disabled={this.state.submitting} outline color="dark" type="submit">
{this.state.submitting === true && <span className="icon icon-spin ion-md-refresh mr-2"/>}
Sign in with email
</Button>
</p>
</Form>
</Col>
</Row>
</React.Fragment>
)
}
}
}
export class SignInButtons extends React.Component {
render() {
return (
<React.Fragment>
{
Object.keys(this.props.providers).map((provider, i) => {
if (!this.props.providers[provider].signin) return null
return (
<p key={i}>
<a className="btn btn-block btn-outline-secondary" href={this.props.providers[provider].signin}>
Sign in with {provider}
</a>
</p>
)
})
}
</React.Fragment>
)
}
}
+40 -81
View File
@@ -1,88 +1,47 @@
import fetch from 'isomorphic-unfetch'
import axios from "axios";
//TODO: 'isomorphic-unfetch' :how to set default headers ?
// var obj = {
// method: 'GET',
// mode: 'no-cors',
// // headers: {
// // 'Access-Control-Request-Headers': 'Authorization',
// // 'Authorization': 'Basic amFzcGVyYWRtaW46amFzcGVyYWRtaW4=',
// // 'Content-Type': 'application/json',
// // 'Origin': ''
// // },
// credentials: 'include'
// };
//axios.defaults.headers.common = { 'X-Requested-With': 'XMLHttpRequest' }
axios.defaults.baseURL = (process.env.NODE_ENV !== 'production') ? 'http://localhost/app_dev.php/' : ''
export default {
ads: {
fetchAd: async (id) => {
const res = await fetch(`http://localhost/app_dev.php/api/ads/${id}`)
const offre = await res.json()
return { offre: offre.data }
user: {
login: credentials =>
axios.post("/api/login_check", { username: credentials.email, password: credentials.password }).then(res => res.data),
loginOauth: ({token,type}) =>
axios.post("/api/login_check_oauth", {'oauth-token':token,'oauth-type':type}),
fetchUser: () =>{
console.log("axios /api/user")
return axios.get("/api/user").then(res => {console.log(res); return res.data})},
subscribeToNewsletter: (data) =>
{
console.log(data)
return axios.post("http://localhost:3000/NewsletterSubscription", data).then(res => {console.log(res); return res})
},
register: (data) => {
console.log(data)
return axios.post("/api/register", { data}).then(res => res)
},
fetchAds: async (limit = "", order = "", keyword = "", offset = 1) => {
var obj = {
method: 'GET',
//mode : 'no-cors',
headers: {
// 'Access-Control-Request-Headers': 'Authorization',
// 'Authorization': 'Basic amFzcGVyYWRtaW46amFzcGVyYWRtaW4=',
'Content-Type': 'application/json',
'Origin': ''
},
credentials: 'include'
};
let url = `http://localhost/app_dev.php/api/ads?offset=${offset}`;
if (limit != "") {
url = url + `&limit=${limit}`;
}
if (order != "") {
url = url + `&order=${order}`;
}
if (keyword != "") {
url = url + `&keyword=${keyword}`;
}
const res = await fetch(url, obj);
const show = await res.json();
return show.data;
}
},
companies:{
fetchCompany: async (id) => {
const res = await fetch(`http://localhost/app_dev.php/api/companies/${id}`)
const company = await res.json()
return { company: company.data }
ads: {
fetchAd: (id) => {
console.debug("--- fetchAd")
console.debug(id)
return axios.get(`api/ads/${id}`).then(res => res.data)
},
fetchCompanies: async (limit = "", order = "", keyword = "", offset = 1) => {
var obj = {
method: 'GET',
//mode : 'no-cors',
headers: {
// 'Access-Control-Request-Headers': 'Authorization',
// 'Authorization': 'Basic amFzcGVyYWRtaW46amFzcGVyYWRtaW4=',
'Content-Type': 'application/json',
'Origin': ''
},
credentials: 'include'
};
let url = `http://localhost/app_dev.php/api/companies?offset=${offset}`;
if (limit != "") {
url = url + `&limit=${limit}`;
}
if (order != "") {
url = url + `&order=${order}`;
}
if (keyword != "") {
url = url + `&keyword=${keyword}`;
}
const res = await fetch(url, obj);
const show = await res.json();
return show.data;
}
//offset is the index position of the first element to start requesting at
// use 0|1 for isPromoted
fetchAds: ({ limit = null, order = "", keyword = "", offset = 1, status='PUBLISHED', isPromoted=null}) => {
console.debug("--- fetchAds" + offset, limit, order, keyword)
return axios.get('api/ads', { params: { offset, limit, order, keyword, status, isPromoted } })
.then(res => res.data)
},
},
companies: {
fetchCompany: id =>
axios.get(`api/companies/${id}`).then(res => res.data),
fetchCompanies: (limit = "", order = "", keyword = "", offset = 1) =>
axios.get('api/companies', { params: { offset, limit, order, keyword } }).then(res => res.data)
}
}
};
+9
View File
@@ -0,0 +1,9 @@
import axios from "axios";
export default (token = null) => {
if (token) {
axios.defaults.headers.common.authorization = `Bearer ${token}`;
} else {
delete axios.defaults.headers.common.authorization;
}
};
Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

+3 -10
View File
@@ -1,14 +1,7 @@
/**
* next-auth.config.js Example
*
* Environment variables for this example:
*
* PORT=3000
* SERVER_URL=http://localhost:3000
* MONGO_URI=mongodb://localhost:27017/my-database
*
* If you wish, you can put these in a `.env` to seperate your environment
* specific configuration from your code.
*
*
*
**/
// Load environment variables from a .env file if one exists
+1 -1
View File
@@ -55,7 +55,7 @@ module.exports = () => {
providerOptions: {
scope: ['r_emailaddress', 'r_basicprofile']
},
Strategy: require('passport-linkedin-oauth2').Strategy,
Strategy: require('@sokratis/passport-linkedin-oauth2').Strategy,
strategyOptions: {
clientID: process.env.LINKEDIN_ID,
clientSecret: process.env.LINKEDIN_SECRET,
+85 -41
View File
@@ -1,52 +1,96 @@
// next.config.js
const withPlugins = require('next-compose-plugins');
const optimizedImages = require('next-optimized-images');
const webpack = require("webpack");
const withPlugins = require('next-compose-plugins')
const optimizedImages = require('next-optimized-images')
const webpack = require("webpack")
const withCSS = require('@ostai/next-css')
const withOffline = require('next-offline')
const { ANALYZE, DEV } = process.env
module.exports = withPlugins([
[withCSS],
[optimizedImages, {
/* config for next-optimized-images */
}],
[withOffline, {
dontAutoRegisterSw: DEV ? true : false,
workboxOpts: {
globPatterns: ['static/**/*'],
globDirectory: '.',
runtimeCaching: [
// { urlPattern: /.*auth.*/, handler: 'networkOnly' },
// { urlPattern: /.*account.*/, handler: 'networkOnly' },
{ urlPattern: /^https?.*/, handler: 'networkFirst' },
{ urlPattern: /\.(?:png|jpg|jpeg|svg|webp)$/,
handler: "cacheFirst",
options: {
cacheName: "images",
expiration: {
maxEntries: 100
}
}}
],
importScripts:
['/static/js/firebase-messaging-sw.js',
'/static/js/backgroundSync-sw.js'
]
},
// your other plugins here
// {
// webpack: (config, { isServer }) => {
// // config.module.noParse = /jpg/;
}],
// // config.module.rules.push(
// // {
// // test: /\.js$/,
// // loader: 'babel-loader',
// // exclude: /node_modules/,
// // },
// // {
// // test: /\.css$/,
// // loader: 'style!css'
// // },
// // {
// // test: /\.html$/,
// // loader: 'raw'
// // }
// // )
[{
publicRuntimeConfig: {
// // const videojsPlugin = new webpack.ProvidePlugin({
// // videojs: "video.js/dist/video.cjs.js",
// // RecordRTC: "recordrtc",
// // MediaStreamRecorder: ["recordrtc", "MediaStreamRecorder"]
// // });
// // const videojsAlias = {
// // videojs: "video.js",
// // WaveSurfer: "wavesurfer.js",
// // RecordRTC: "recordrtc"
// // };
// // config.resolve.alias = { ...config.resolve.alias, ...videojsAlias };
// // config.plugins.push(videojsPlugin);
adListDefaultUrl: "https://www.talentstube.com/img/default_picture_company.svg",
logoRootUrl: 'https://www.talentstube.com/media/cache/profile_thumb/uploads/img/'
}
}]],
{
webpack: (config, { isServer }) => {
// return config
// }
if (ANALYZE) {
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
]);
config.plugins.push(new BundleAnalyzerPlugin({
analyzerMode: 'server',
analyzerPort: isServer ? 8888 : 8889,
openAnalyzer: true
}))
}
const videojsPlugin = new webpack.ProvidePlugin({
videojs: "video.js/dist/video.cjs.js",
RecordRTC: "recordrtc",
MediaStreamRecorder: ["recordrtc", "MediaStreamRecorder"]
});
const videojsAlias = {
videojs: "video.js",
WaveSurfer: "wavesurfer.js",
RecordRTC: "recordrtc"
};
config.resolve.alias = { ...config.resolve.alias, ...videojsAlias };
config.plugins.push(videojsPlugin);
// config.module.rules.push(
// {
// test: /\.css$/,
// loader: 'style-loader!css-loader',
// include: [/node_modules/]
// },
// )
console.log(config);
return config
}
},
{
generateBuildId: async () => {
// For example get the latest git commit hash here
return 'v0.1.0'
}
},
);
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../acorn/bin/acorn" "$@"
ret=$?
else
node "$basedir/../acorn/bin/acorn" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\acorn\bin\acorn" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\acorn\bin\acorn" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../ansi-html/bin/ansi-html" "$@"
ret=$?
else
node "$basedir/../ansi-html/bin/ansi-html" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\ansi-html\bin\ansi-html" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\ansi-html\bin\ansi-html" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../atob/bin/atob.js" "$@"
ret=$?
else
node "$basedir/../atob/bin/atob.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\atob\bin\atob.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\atob\bin\atob.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../bin-version-check/cli.js" "$@"
ret=$?
else
node "$basedir/../bin-version-check/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\bin-version-check\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\bin-version-check\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../browserslist/cli.js" "$@"
ret=$?
else
node "$basedir/../browserslist/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\browserslist\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\browserslist\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../color-support/bin.js" "$@"
ret=$?
else
node "$basedir/../color-support/bin.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\color-support\bin.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\color-support\bin.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../cwebp-bin/cli.js" "$@"
ret=$?
else
node "$basedir/../cwebp-bin/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\cwebp-bin\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\cwebp-bin\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../errno/cli.js" "$@"
ret=$?
else
node "$basedir/../errno/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\errno\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\errno\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../eslint/bin/eslint.js" "$@"
ret=$?
else
node "$basedir/../eslint/bin/eslint.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\eslint\bin\eslint.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\eslint\bin\eslint.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../esprima/bin/esparse.js" "$@"
ret=$?
else
node "$basedir/../esprima/bin/esparse.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\esprima\bin\esparse.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\esprima\bin\esparse.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../esprima/bin/esvalidate.js" "$@"
ret=$?
else
node "$basedir/../esprima/bin/esvalidate.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\esprima\bin\esvalidate.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\esprima\bin\esvalidate.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../executable/cli.js" "$@"
ret=$?
else
node "$basedir/../executable/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\executable\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\executable\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../find-versions/cli.js" "$@"
ret=$?
else
node "$basedir/../find-versions/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\find-versions\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\find-versions\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../gifsicle/cli.js" "$@"
ret=$?
else
node "$basedir/../gifsicle/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\gifsicle\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\gifsicle\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../he/bin/he" "$@"
ret=$?
else
node "$basedir/../he/bin/he" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\he\bin\he" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\he\bin\he" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../image-size/bin/image-size.js" "$@"
ret=$?
else
node "$basedir/../image-size/bin/image-size.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\image-size\bin\image-size.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\image-size\bin\image-size.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../is-ci/bin.js" "$@"
ret=$?
else
node "$basedir/../is-ci/bin.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\is-ci\bin.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\is-ci\bin.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../js-yaml/bin/js-yaml.js" "$@"
ret=$?
else
node "$basedir/../js-yaml/bin/js-yaml.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\js-yaml\bin\js-yaml.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\js-yaml\bin\js-yaml.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../jsesc/bin/jsesc" "$@"
ret=$?
else
node "$basedir/../jsesc/bin/jsesc" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\jsesc\bin\jsesc" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\jsesc\bin\jsesc" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../json5/lib/cli.js" "$@"
ret=$?
else
node "$basedir/../json5/lib/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\json5\lib\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\json5\lib\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../jsonlint/lib/cli.js" "$@"
ret=$?
else
node "$basedir/../jsonlint/lib/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\jsonlint\lib\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\jsonlint\lib\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../loose-envify/cli.js" "$@"
ret=$?
else
node "$basedir/../loose-envify/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\loose-envify\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\loose-envify\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../lpad-align/cli.js" "$@"
ret=$?
else
node "$basedir/../lpad-align/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\lpad-align\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\lpad-align\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../miller-rabin/bin/miller-rabin" "$@"
ret=$?
else
node "$basedir/../miller-rabin/bin/miller-rabin" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\miller-rabin\bin\miller-rabin" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\miller-rabin\bin\miller-rabin" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../mime/cli.js" "$@"
ret=$?
else
node "$basedir/../mime/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\mime\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\mime\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../mkdirp/bin/cmd.js" "$@"
ret=$?
else
node "$basedir/../mkdirp/bin/cmd.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\mkdirp\bin\cmd.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\mkdirp\bin\cmd.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../mozjpeg/cli.js" "$@"
ret=$?
else
node "$basedir/../mozjpeg/cli.js" "$@"
ret=$?
fi
exit $ret
-7
View File
@@ -1,7 +0,0 @@
@IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\mozjpeg\cli.js" %*
) ELSE (
@SETLOCAL
@SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\mozjpeg\cli.js" %*
)
-15
View File
@@ -1,15 +0,0 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac
if [ -x "$basedir/node" ]; then
"$basedir/node" "$basedir/../next/dist/bin/next" "$@"
ret=$?
else
node "$basedir/../next/dist/bin/next" "$@"
ret=$?
fi
exit $ret

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