Skip to content
This repository has been archived by the owner on May 16, 2020. It is now read-only.

Commit

Permalink
refactor: Add Next application
Browse files Browse the repository at this point in the history
  • Loading branch information
omaralbeik committed Aug 18, 2019
1 parent 7878fb1 commit e6feb3f
Show file tree
Hide file tree
Showing 181 changed files with 6,797 additions and 12,906 deletions.
17 changes: 17 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"presets": [ "next/babel" ],
"plugins": [
"inline-react-svg",
[ "babel-plugin-styled-components",
{
"ssr": true,
"displayName": true,
"minify": true,
"preprocess": false
}
],
[ "module-resolver",
{ "root": ["./"] }
]
]
}
72 changes: 60 additions & 12 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,21 +1,69 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release

# dependencies
/node_modules
# Dependency directories
node_modules/
jspm_packages/

# testing
/coverage
# TypeScript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env

# next.js build output
.next

# production
/build

# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local

npm-debug.log*
yarn-debug.log*
yarn-error.log*
.env.production.local
12 changes: 12 additions & 0 deletions components/about-cover/_styled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import styled from 'styled-components';
import Img from 'react-image';
import { sm, md } from 'styles/breakpoints';

export const _Img = styled(Img)`
width: 100%;
border-radius: 8px;
margin-bottom: 40px;
@media (${sm}), (${md}) {
display: none;
}
`;
5 changes: 5 additions & 0 deletions components/about-cover/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { _Img } from './_styled';

const AboutCover = _Img;

export default AboutCover;
11 changes: 11 additions & 0 deletions components/active-link/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Children } from 'react';
import Link from 'next/link';
import { withRouter } from 'next/router';

const ActiveLink = withRouter(({ router, children, ...props }) => (
<Link {...props}>
{React.cloneElement(Children.only(children), { className: `/${router.pathname.split("/")[1]}` === props.href ? `active` : null })}
</Link>
));

export default ActiveLink;
5 changes: 5 additions & 0 deletions components/api-row/_styled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import styled from 'styled-components';

export const _a = styled.a`
font-family: ${ props => props.theme.fonts.mono } !important;
`;
33 changes: 33 additions & 0 deletions components/api-row/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { _a } from './_styled';
import { withTheme } from 'styled-components';

class APIRow extends Component {

static propTypes = {
item: PropTypes.object.isRequired,
isUrl: PropTypes.bool
}

render() {
const { item, isUrl=true } = this.props;

return (
<tr>
<th scope='row'>
{
isUrl
? <_a href={item.url} target='_blank' rel='noopener noreferrer'>{item.name}</_a>
: <p>{item.name}</p>
}
</th>
<td>{item.method}</td>
<td>{item.description}</td>
</tr>
);
}

}

export default withTheme(APIRow);
6 changes: 6 additions & 0 deletions components/api-table/_styled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import styled from 'styled-components';
import { Table } from 'reactstrap';

export const _Table = styled(Table)`
margin-top: 50px;
`;
5 changes: 5 additions & 0 deletions components/api-table/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { _Table } from './_styled';

const APITable = _Table;

export default APITable;
48 changes: 48 additions & 0 deletions components/contact-form/_styled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import styled from 'styled-components';
import { sm } from 'styles/breakpoints';
import InnerContainer from '../inner-container';
import { Col, Form, FormGroup, Label, Input, Button } from 'reactstrap';

export const _Col = Col;
export const _Form = Form;
export const _FormGroup = FormGroup;

export const _InnerContainer = styled(InnerContainer)`
padding: 50px 50px 30px 50px;
border-radius: 8px;
margin: 15px 0 10px 0;
border-top: 10px solid;
box-shadow: 0 3px 5px rgba(0, 0, 0, 0.05);
@media (${sm}) {
padding: 20px;
}
`;

export const _Label = styled(Label)`
@media (${sm}) {
display: none;
}
`;

export const _Input = styled(Input)`
background-color: ${props => props.theme.colors.background};
color: ${props => props.theme.colors.primary};
border: none;
box-shadow: none;
-webkit-appearance: none;
&:focus {
background-color: ${props => props.theme.colors.background};
border: 1px solid ${props => props.theme.colors.highlighted};
color: ${props => props.theme.colors.primary};
box-shadow: none;
}
`;

export const _Button = styled(Button)`
:disabled {
cursor: not-allowed;
}
@media (${sm}) {
width: 100%;
}
`;
154 changes: 154 additions & 0 deletions components/contact-form/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Toast from 'cogo-toast';
import { _h2, _InnerContainer, _Col, _Form, _FormGroup, _Label, _Input, _Button } from './_styled';
import { countries, contactStrings } from 'static/strings';
import ReCAPTCHA from 'components/recaptcha';
import APIHelper from 'utils/api-helper';

class ContactForm extends Component {

initialState = {
name: "",
email: "",
phone: "",
country: "",
city: "",
subject: "",
message: "",
is_valid: false
}
state = this.initialState;
reCaptchaRef = React.createRef();

handleChange = async event => {
const { name, value } = event.target;
await this.setState(oldState => ({
...oldState,
[name]: value
}));
}

onReCAPTCHAChange = response => {
this.setState(oldState => ({
...oldState,
recaptcha_response: response
}));
}

showAlert = (message, success) => {
const options = { position: 'bottom-center', hideAfter: 5 };
if (success) {
Toast.success(message, options);
} else {
Toast.error(message, options);
}
}

handleSubmit = async event => {
event.preventDefault();
try {
const message = await APIHelper.sendContactMessage(this.state);
this.setState(this.initialState);
this.reCaptchaRef.current.reset();
this.showAlert(contactStrings.success, true);
}
catch (error) {
console.error(error);
this.showAlert(error, false);
}
}

render() {
const { onSubmit } = this.props;
const { name, email, phone, country, city, subject, message, recaptcha_response } = this.state;
const isValid = (name && email && subject && message && recaptcha_response);

return (
<div>
<_InnerContainer>
<_Form onSubmit={this.handleSubmit}>
<_FormGroup row>
<_Label for='name' md={3} hide='xs'>{contactStrings.namePlaceholder} *</_Label>
<_Col md={9} sm={12}>
<_Input type='text' name='name' id='name'
placeholder={contactStrings.namePlaceholder}
value={name}
onChange={this.handleChange}
/>
</_Col>
</_FormGroup>
<_FormGroup row>
<_Label for='email' md={3} hide='xs'>{contactStrings.emailPlaceholder} *</_Label>
<_Col md={9} sm={12}>
<_Input type='email' name='email' id='email'
placeholder={contactStrings.emailPlaceholder}
value={email}
onChange={this.handleChange}
/>
</_Col>
</_FormGroup>
<_FormGroup row>
<_Label for='phone' md={3} hide='xs'>{contactStrings.phonePlaceholder}</_Label>
<_Col md={9} sm={12}>
<_Input type='tel' name='phone' id='phone'
placeholder={contactStrings.phonePlaceholder}
value={phone}
onChange={this.handleChange}
/>
</_Col>
</_FormGroup>
<_FormGroup row>
<_Label for='country' md={3} hide='xs'>{contactStrings.countryPlaceholder}</_Label>
<_Col md={9} sm={12}>
<_Input type='select' name='country' id='country' value={country} onChange={this.handleChange}>
<option value=''>{contactStrings.defaultCountry}</option>
{countries.map((c, i) => (<option key={i} value={c}>{c}</option>))}
<option>1</option>
</_Input>
</_Col>
</_FormGroup>
<_FormGroup row>
<_Label for='city' md={3} hide='xs'>{contactStrings.cityPlaceholder}</_Label>
<_Col md={9} sm={12}>
<_Input type='text' name='city' id='city'
placeholder={contactStrings.cityPlaceholder}
value={city}
onChange={this.handleChange}
/>
</_Col>
</_FormGroup>
<_FormGroup row>
<_Label for='subject' md={3} hide='xs'>{contactStrings.subjectPlaceholder} *</_Label>
<_Col md={9} sm={12}>
<_Input type='text' name='subject' id='subject'
placeholder={contactStrings.subjectPlaceholder}
value={subject}
onChange={this.handleChange}
/>
</_Col>
</_FormGroup>
<_FormGroup row>
<_Label for='message' md={3} hide='xs'>{contactStrings.messagePlaceholder} *</_Label>
<_Col md={9} sm={12}>
<_Input type='textarea' name="message" id='message' rows={10}
placeholder={contactStrings.messagePlaceholder}
value={message}
onChange={this.handleChange}
/>
</_Col>
</_FormGroup>
<ReCAPTCHA onChange={this.onReCAPTCHAChange} ref={this.reCaptchaRef} />
<_FormGroup row>
<_Col sm={12}>
<_Button disabled={!isValid} className='float-right'>{contactStrings.submit}</_Button>
</_Col>
</_FormGroup>
</_Form>
</_InnerContainer>
</div>
);
}
}

export default ContactForm;
Loading

0 comments on commit e6feb3f

Please sign in to comment.