├── .env.example ├── .gitignore ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── CONTRIBUTE.md ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── public ├── favicon.ico ├── index.html ├── logo192.png ├── logo512.png ├── manifest.json └── robots.txt ├── src ├── __tests__ │ ├── App.test.js │ ├── CoderCard.test.js │ └── DominicansWhoCodesList.test.js ├── components │ ├── CoderCard.js │ └── layout │ │ ├── Footer.js │ │ ├── Header.js │ │ └── PageInfo.js ├── containers │ ├── App.js │ └── DominicansWhoCodesList.js ├── hooks │ └── useDominicanCoders.js ├── index.js ├── sass │ ├── base │ │ ├── _base.scss │ │ ├── _variables.scss │ │ └── index.scss │ ├── components │ │ ├── _app.scss │ │ ├── _dev.scss │ │ └── index.scss │ ├── helpers │ │ ├── _animations.scss │ │ └── index.scss │ └── index.scss ├── setupTests.js └── utils │ ├── data.js │ └── index.js └── yarn.lock /.env.example: -------------------------------------------------------------------------------- 1 | REACT_APP_API_URL=https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/master/DominicanWhoCodes.Blazor/wwwroot/data/developers.json 2 | REACT_APP_ROOT_URL=https://raw.githubusercontent.com/AngelGarcia13/DominicanWhoCodes/master/DominicanWhoCodes.Blazor/wwwroot/ 3 | REACT_APP_PROJECT_NAME="Dominicans Who Codes" -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | */__tests__/__snapshots__ 11 | 12 | # production 13 | /build 14 | 15 | # misc 16 | .DS_Store 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* 25 | .env 26 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "stable" 4 | cache: 5 | directories: 6 | - node_modules 7 | install: 8 | - yarn install 9 | script: 10 | - yarn test 11 | - yarn build 12 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at 59 | [React Dominicana - Whatsapp Group](https://chat.whatsapp.com/ErGzklqgz8Q1Wjj9BaJTvk). All 60 | complaints will be reviewed and investigated and will result in a response that 61 | is deemed necessary and appropriate to the circumstances. The project team is 62 | obligated to maintain confidentiality with regard to the reporter of an incident. 63 | Further details of specific enforcement policies may be posted separately. 64 | 65 | Project maintainers who do not follow or enforce the Code of Conduct in good 66 | faith may face temporary or permanent repercussions as determined by other 67 | members of the project's leadership. 68 | 69 | ## Attribution 70 | 71 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 72 | available at [http://contributor-covenant.org/version/1/4][version] 73 | 74 | [homepage]: http://contributor-covenant.org 75 | [version]: http://contributor-covenant.org/version/1/4/ -------------------------------------------------------------------------------- /CONTRIBUTE.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | 👍🎉 First off all, thanks for taking the time to contribute! 🎉👍 4 | 5 | When contributing to this repository, please first discuss the change you wish to make via issue, 6 | email, or any other method with the owners of this repository before making a change. 7 | 8 | Please note we have a code of conduct, please follow it in all your interactions with the project. 9 | 10 | ## How can I Contribute? 11 | 12 | ### Reporting Bugs 13 | 14 | Bugs are tracker as [GitHub issues](https://github.com/React-Dominicana/dominicans-who-code-react/issues). 15 | Explain the problem and include additional details to help maintainers reproduce the proble: 16 | 17 | - **Use a clear and descriptive title** for the issue to identify the problem. 18 | - **Describe the exact steps which reproduce the problem** in as many details as possible. 19 | For example, start by explaining how you started the project, e.g. which command exactly you used 20 | in the terminal, or how you started the project otherwise. 21 | - **Provide specific examples to demonstrate the steps**. Include links to files, or copy/paste snippets, 22 | which you use in those examples. If you're providing snippets in the issue, use [Markdown code blocks](https://help.github.com/en/articles/getting-started-with-writing-and-formatting-on-github#multiple-lines). 23 | - **Describe the behavior you observed after following the steps** and point out what exactly is the problem with that behavior. 24 | - **Explain which behavior you expected** to see instead and why. 25 | - **Include screenshots and animated GIFs** which show you following the described steps and clearly demonstrate the problem. 26 | 27 | ### Suggesting Enhancements 28 | 29 | Before creating enhancement suggestions, please check this 30 | [list](https://github.com/React-Dominicana/dominicans-who-code-react/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement) 31 | as you might find out that you don't need to create one. When you are creating an enhancement suggestion, 32 | please include as many details as possible. 33 | 34 | - **Use a clear and descriptive title** for the issue to indentify the suggestion. 35 | - **Provide a step-by-step description of the suggested enhancement** in as many details as possible. 36 | - **Provide specific examples to demonstrate the steps**. Include copy/pasteable snippets which you use 37 | in those examples, as [Markdown code blocks](https://help.github.com/en/articles/getting-started-with-writing-and-formatting-on-github#multiple-lines). 38 | - **Describe the current behavior** and explain which behavior you expected to see instead and why. 39 | - **Include screenshots and animated GIFs** which help you demonstrate the steps or point out the part 40 | of Atom which the suggestion is related to. 41 | 42 | ### Pull Request Process 43 | 44 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a build. 45 | 2. Update the README.md with details of changes to the interface, this includes new environment variables, 46 | exposed ports, useful file locations and container parameters. 47 | 3. After you submit your Pull Request, verify that all 48 | [status checks](https://help.github.com/en/articles/about-status-checks) are passing. 49 | 4. You may merge the Pull Request in once you have the sign-off of at least of one developer, or 50 | if you do not have permission to do that, you may request the reviewer to merge it for you. 51 | 52 | ## Styleguides 53 | 54 | ### Git Commit Messages 55 | 56 | - Use the present tense ("Add feature" not "Added feature") 57 | - Use the imperative mood ("Move cursor to..." not "Moves cursor to...") 58 | - Limit the first line to 72 characters or less 59 | - Reference issues and pull requests liberally after the first line 60 | - When only changing documentation, include [ci skip] in the commit title 61 | - Consider starting the commit message with an applicable emoji: 62 | - 🎨 :art: when improving the format/structure of the code 63 | - 🐎 :racehorse: when improving performance 64 | - 🚱 :non-potable_water: when plugging memory leaks 65 | - 📝 :memo: when writing docs 66 | - 🐧 :penguin: when fixing something on Linux 67 | - 🍎 :apple: when fixing something on macOS 68 | - 🏁 :checkered_flag: when fixing something on Windows 69 | - 🐛 :bug: when fixing a bug 70 | - 🔥 :fire: when removing code or files 71 | - 💚 :green_heart: when fixing the CI build 72 | - ✅ :white_check_mark: when adding tests 73 | - 🔒 :lock: when dealing with security 74 | - ⬆️ :arrow_up: when upgrading dependencies 75 | - ⬇️ :arrow_down: when downgrading dependencies 76 | - 👕 :shirt: when removing linter warnings 77 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 React Dominicana 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DominicanWhoCodes - React 2 | 3 | Open source project inspired in [IndiansWhoDesign](http://indianswhodesign.in), made to expose all the developers from the Dominican Republic with their skills and contacts. 4 | 5 | ### Prerequisites 6 | 7 | - Node 8 | - Yarn 9 | 10 | ### Installation 11 | 12 | #### Yarn 13 | 14 | ``` 15 | yarn install 16 | ``` 17 | 18 | ### Development 19 | 20 | > *NOTE*: rename the `.env.example` to `.env`. 21 | 22 | #### Yarn 23 | 24 | ``` 25 | yarn start 26 | ``` 27 | 28 | ### Tests 29 | 30 | #### Yarn 31 | 32 | To run the tests. 33 | 34 | ``` 35 | yarn test 36 | ``` 37 | 38 | To run the tests with `watch`. 39 | 40 | ``` 41 | yarn test:watch 42 | ``` 43 | 44 | To run the tests with `watch` and `coverage`. 45 | 46 | ``` 47 | yarn test:coverage 48 | ``` 49 | 50 | ### Deployment 51 | 52 | Automatically deployed into [Netlify](https://www.netlify.com/) when the `master` branch is updated. 53 | 54 | ### Acknowledgments 55 | 56 | - [DominicanWhoCodes](https://github.com/AngelGarcia13/DominicanWhoCodes) 57 | - [IndiansWhoDesign](http://indianswhodesign.in) 58 | 59 | ### License 60 | 61 | This project uses the following license: [MIT]() 62 | 63 |

With ❤️ from 🌴

-------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dominicans-who-code", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "react-scripts start", 7 | "build": "react-scripts build", 8 | "test": "cross-env CI=true react-scripts test --env=jsdom --coverage", 9 | "test:coverage": "react-scripts test --env=jsdom --coverage", 10 | "test:watch": "react-scripts test --env=jsdom", 11 | "eject": "react-scripts eject" 12 | }, 13 | "eslintConfig": { 14 | "extends": "react-app" 15 | }, 16 | "browserslist": { 17 | "production": [ 18 | ">0.2%", 19 | "not dead", 20 | "not op_mini all" 21 | ], 22 | "development": [ 23 | "last 1 chrome version", 24 | "last 1 firefox version", 25 | "last 1 safari version" 26 | ] 27 | }, 28 | "jest": { 29 | "snapshotSerializers": [ 30 | "enzyme-to-json/serializer" 31 | ] 32 | }, 33 | "dependencies": { 34 | "@fortawesome/fontawesome-svg-core": "^1.2.22", 35 | "@fortawesome/free-brands-svg-icons": "^5.10.2", 36 | "@fortawesome/free-solid-svg-icons": "^5.10.2", 37 | "@fortawesome/react-fontawesome": "^0.1.4", 38 | "node-sass": "^4.12.0", 39 | "react": "^16.9.0", 40 | "react-dom": "^16.9.0", 41 | "react-scripts": "3.1.1", 42 | "reactstrap": "8.0.1" 43 | }, 44 | "devDependencies": { 45 | "cross-env": "^6.0.0", 46 | "enzyme": "^3.10.0", 47 | "enzyme-adapter-react-16": "^1.14.0", 48 | "enzyme-to-json": "^3.4.0", 49 | "pre-commit": "^1.2.2" 50 | }, 51 | "pre-commit": [ 52 | "test" 53 | ] 54 | } 55 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-Dominicana/dominicans-who-code-react/62339bf0d68472c46dc95751c91ac87de784f8f0/public/favicon.ico -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 14 | 18 | 19 | 28 | Dominicans Who Code 29 | 30 | 31 | 32 |
33 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-Dominicana/dominicans-who-code-react/62339bf0d68472c46dc95751c91ac87de784f8f0/public/logo192.png -------------------------------------------------------------------------------- /public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/React-Dominicana/dominicans-who-code-react/62339bf0d68472c46dc95751c91ac87de784f8f0/public/logo512.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | -------------------------------------------------------------------------------- /src/__tests__/App.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import { shallow } from 'enzyme' 4 | 5 | import { App } from '../containers/App' 6 | 7 | describe('App', () => { 8 | 9 | it('renders without crashing', () => { 10 | const div = document.createElement("div"); 11 | ReactDOM.render(, div); 12 | ReactDOM.unmountComponentAtNode(div); 13 | }) 14 | 15 | it('should render correctly with no props', () => { 16 | const component = shallow(); 17 | expect(component).toMatchSnapshot(); 18 | }) 19 | 20 | it('should render correctly in "debug" mode', () => { 21 | const component = shallow(); 22 | expect(component).toMatchSnapshot(); 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /src/__tests__/CoderCard.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import { shallow } from 'enzyme' 4 | 5 | import { CoderCard } from '../components/CoderCard' 6 | import { coder1, coder2, coder3 } from '../utils/data' 7 | 8 | 9 | describe('CoderCard', () => { 10 | let wrapper 11 | 12 | const coders = [coder1, coder2, coder3] 13 | 14 | beforeEach(() => { 15 | wrapper = coders.map(coder => shallow().dive()) 16 | }) 17 | 18 | describe('on start', () => { 19 | 20 | it('load the images', () => { 21 | for (let w of wrapper) { 22 | const image = w.find('Card').getElement().props.children[0].props.children 23 | expect(image === (coders[wrapper.indexOf(w)].image)) 24 | } 25 | }) 26 | 27 | it('load the links', () => { 28 | for (let w of wrapper) { 29 | const _links = w.find('CardBody').getElement().props.children[0] 30 | for (let _link of _links) { 31 | expect(coders[wrapper.indexOf(w)].links.includes(_link)) 32 | } 33 | } 34 | }) 35 | 36 | it('load the names', () => { 37 | for (let w of wrapper) { 38 | const name = w.find('CardBody').getElement().props.children[1].props.children 39 | expect(name === (coders[wrapper.indexOf(w)].name)) 40 | } 41 | }) 42 | 43 | it('load the initials', () => { 44 | for (let w of wrapper) { 45 | const initials = w.find('CardBody').getElement().props.children[2].props.children 46 | expect(initials === (coders[wrapper.indexOf(w)].initials)) 47 | } 48 | }) 49 | 50 | it('load the summaries', () => { 51 | for (let w of wrapper) { 52 | const summary = w.find('CardBody').getElement().props.children[3].props.children 53 | expect(summary === (coders[wrapper.indexOf(w)].summary)) 54 | } 55 | }) 56 | 57 | it('load the skills', () => { 58 | for (let w of wrapper) { 59 | const skills = w.find('CardBody').getElement().props.children[4].props.children 60 | expect(skills === (coders[wrapper.indexOf(w)].skills)) 61 | } 62 | }) 63 | 64 | it('should render 3 coders', () => { 65 | expect(wrapper).toHaveLength(3) 66 | }) 67 | 68 | it('should render correctly one coder', () => { 69 | const component = shallow() 70 | expect(component).toMatchSnapshot() 71 | }) 72 | 73 | it('renders without crashing', () => { 74 | const div = document.createElement("div"); 75 | ReactDOM.render(, div); 76 | ReactDOM.unmountComponentAtNode(div); 77 | }) 78 | 79 | }) 80 | 81 | }) 82 | -------------------------------------------------------------------------------- /src/__tests__/DominicansWhoCodesList.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import { shallow } from 'enzyme' 4 | 5 | import { DominicansWhoCodesList } from '../containers/DominicansWhoCodesList' 6 | 7 | describe('DominicansWhoCodesList', () => { 8 | 9 | it('renders without crashing', () => { 10 | const div = document.createElement("div"); 11 | ReactDOM.render(, div); 12 | ReactDOM.unmountComponentAtNode(div); 13 | }) 14 | 15 | it('should render correctly with no props', () => { 16 | const component = shallow(); 17 | expect(component).toMatchSnapshot(); 18 | }) 19 | 20 | it('should render correctly in "debug" mode', () => { 21 | const component = shallow(); 22 | expect(component).toMatchSnapshot(); 23 | }) 24 | 25 | }) 26 | 27 | -------------------------------------------------------------------------------- /src/components/CoderCard.js: -------------------------------------------------------------------------------- 1 | import React, { memo } from 'react' 2 | import Col from 'reactstrap/lib/Col' 3 | import Card from 'reactstrap/lib/Card' 4 | import CardTitle from 'reactstrap/lib/CardTitle' 5 | import CardSubtitle from 'reactstrap/lib/CardSubtitle' 6 | import CardText from 'reactstrap/lib/CardText' 7 | import CardBody from 'reactstrap/lib/CardBody' 8 | import Badge from 'reactstrap/lib/Badge' 9 | import Row from 'reactstrap/lib/Row' 10 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' 11 | 12 | export const CoderCard = memo((props) => { 13 | const skills = props.skills.split(',') 14 | 15 | const renderSkillsTag = (skill, index) => 16 | {skill} 17 | 18 | const renderIconsAndLinks = (link, index) => { 19 | const isPlaceholderLink = () => link.url === '#' ? 'd-none' : '' 20 | return ( 21 | 22 | 23 | 24 | ); 25 | } 26 | 27 | return ( 28 | 29 | 30 |
33 | 34 | {skills.map(renderSkillsTag)} 35 | {props.name} 36 | {props.initials} 37 | {props.summary} 38 | 39 | {props.links.map(renderIconsAndLinks)} 40 | 41 | 42 | 43 | 44 | 45 | ) 46 | }) 47 | -------------------------------------------------------------------------------- /src/components/layout/Footer.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Navbar from 'reactstrap/lib/Navbar' 4 | import NavbarBrand from 'reactstrap/lib/NavbarBrand' 5 | import Nav from 'reactstrap/lib/Nav' 6 | import NavItem from 'reactstrap/lib/NavItem' 7 | import NavLink from 'reactstrap/lib/NavLink' 8 | 9 | export const Footer = () => ( 10 | 11 | {process.env.REACT_APP_PROJECT_NAME} 12 | 17 | 18 | ) 19 | 20 | -------------------------------------------------------------------------------- /src/components/layout/Header.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Navbar from 'reactstrap/lib/Navbar' 4 | import NavbarBrand from 'reactstrap/lib/NavbarBrand' 5 | import Nav from 'reactstrap/lib/Nav' 6 | import NavItem from 'reactstrap/lib/NavItem' 7 | import NavLink from 'reactstrap/lib/NavLink' 8 | 9 | export const Header = () => { 10 | return ( 11 | 12 | {process.env.REACT_APP_PROJECT_NAME} 13 | 21 | 22 | ) 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/components/layout/PageInfo.js: -------------------------------------------------------------------------------- 1 | import React, { memo } from 'react' 2 | 3 | export const PageInfo = memo(() => ( 4 | <> 5 |

Dominicans Who Codes

6 |

Dominican Developers 7 | 8 |  🇩🇴 9 | 10 | who likes to code and contribute to Open Source 11 | 12 |  ❤️ 13 | 14 |

15 | 16 | )) 17 | -------------------------------------------------------------------------------- /src/containers/App.js: -------------------------------------------------------------------------------- 1 | // Helpers 2 | import React, { memo } from 'react' 3 | import { DominicansWhoCodesList } from './DominicansWhoCodesList' 4 | 5 | import { Header } from '../components/layout/Header' 6 | import { Footer } from '../components/layout/Footer' 7 | import { PageInfo } from '../components/layout/PageInfo' 8 | 9 | export const App = memo(() => { 10 | return ( 11 |
12 |
13 | 14 | 15 |
16 |
17 | ); 18 | }); 19 | -------------------------------------------------------------------------------- /src/containers/DominicansWhoCodesList.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Row from 'reactstrap/lib/Row' 4 | import { CoderCard } from '../components/CoderCard' 5 | import { useDominicanCoders } from '../hooks/useDominicanCoders' 6 | 7 | export const DominicansWhoCodesList = () => { 8 | const { data, loading } = useDominicanCoders() 9 | 10 | const renderCodersCards = (coder, index) => 11 | 12 | 13 | return loading ? 'Loading' 14 | : ({data.map(renderCodersCards)}) 15 | } 16 | -------------------------------------------------------------------------------- /src/hooks/useDominicanCoders.js: -------------------------------------------------------------------------------- 1 | import { useState, useEffect } from 'react' 2 | import { checkUrl, shuffle, pathOr } from '../utils' 3 | import { faGlobeAmericas } from '@fortawesome/free-solid-svg-icons' 4 | import { faTwitter, faGithub, faLinkedin } from '@fortawesome/free-brands-svg-icons' 5 | 6 | const buildUrl = criteria => 7 | `${process.env.REACT_APP_API_URL}${criteria ? `/${criteria}` : ''}` 8 | 9 | const isOk = response => 10 | response.ok ? 11 | response.json() : 12 | Promise.reject(response.statusText) 13 | 14 | const appendRawGitUrl = coder => { 15 | const imageStatus = checkUrl(coder.image) 16 | 17 | return { 18 | ...coder, 19 | image: (imageStatus === 1) 20 | ? coder.image 21 | : (imageStatus === 0) 22 | ? `${process.env.REACT_APP_ROOT_URL}${coder.image}` 23 | : 'https://picsum.photos/200' 24 | } 25 | } 26 | 27 | const appendSocialLinks = coder => { 28 | const github = pathOr('#', 'github', coder) 29 | const linkedin = pathOr('#', 'linkedin', coder) 30 | const webpage = pathOr('#', 'webpage', coder) 31 | const twitter = pathOr('#', 'twitter', coder) 32 | 33 | return { 34 | ...coder, 35 | links: Array.from([ 36 | { url: github, icon: faGithub }, 37 | { url: linkedin, icon: faLinkedin }, 38 | { url: webpage, icon: faGlobeAmericas }, 39 | { url: twitter, icon: faTwitter }] 40 | ) 41 | } 42 | } 43 | 44 | const updateLinks = data => 45 | data.map(appendSocialLinks) 46 | 47 | const updateImageUrl = data => 48 | data.map(appendRawGitUrl) 49 | 50 | export const useDominicanCoders = (criteria = '') => { 51 | const [data, setData] = useState([]) 52 | const [loading, setLoading] = useState(true) 53 | const setCoders = coders => setData(coders) 54 | 55 | useEffect(() => { 56 | setLoading(true) 57 | fetch(buildUrl(criteria)) 58 | .then(isOk) 59 | .then(updateImageUrl) 60 | .then(updateLinks) 61 | .then(shuffle) 62 | .then(setCoders) 63 | .finally(setLoading(false)) 64 | 65 | }, [criteria]) 66 | 67 | return { data, loading } 68 | } 69 | 70 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ReactDOM from 'react-dom' 3 | import './sass/index.scss' 4 | import { App } from './containers/App' 5 | 6 | ReactDOM.render(, document.getElementById('root')) 7 | -------------------------------------------------------------------------------- /src/sass/base/_base.scss: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: $primary-font-family; 4 | -webkit-font-smoothing: antialiased; 5 | -moz-osx-font-smoothing: grayscale; 6 | } 7 | 8 | code { 9 | font-family: $secondary-font-family; 10 | } -------------------------------------------------------------------------------- /src/sass/base/_variables.scss: -------------------------------------------------------------------------------- 1 | /* ---------------------- */ 2 | /* Font families */ 3 | /* ---------------------- */ 4 | 5 | $system: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 6 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 7 | sans-serif; 8 | $code: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 9 | monospace; 10 | 11 | /* ---------------------- */ 12 | /* Color palettes */ 13 | /* ---------------------- */ 14 | 15 | $black-odd: #212529; 16 | $black: #000000; 17 | $white: #FFFFFF; 18 | $gray: #282c34; 19 | $blue-light: #61dafb; 20 | 21 | /* ------------------------------------------------------------ */ 22 | /* Font family */ 23 | /* ------------------------------------------------------------ */ 24 | 25 | $primary-font-family: $system; 26 | $secondary-font-family: $code; 27 | 28 | /* ------------------------------------------------------------ */ 29 | /* Breakpoints */ 30 | /* ------------------------------------------------------------ */ 31 | $sm: 320px; 32 | $md: 768px; 33 | $lg: 1025px; -------------------------------------------------------------------------------- /src/sass/base/index.scss: -------------------------------------------------------------------------------- 1 | @import 'variables'; 2 | @import 'base'; 3 | -------------------------------------------------------------------------------- /src/sass/components/_app.scss: -------------------------------------------------------------------------------- 1 | $block: 'App'; 2 | 3 | .#{$block} { 4 | text-align: center; 5 | 6 | &-logo { 7 | animation: App-logo-spin infinite 20s linear; 8 | height: 40vmin; 9 | pointer-events: none; 10 | } 11 | 12 | &-header { 13 | background-color: $gray; 14 | min-height: 100vh; 15 | display: flex; 16 | flex-direction: column; 17 | align-items: center; 18 | justify-content: center; 19 | font-size: calc(10px + 2vmin); 20 | color: $white; 21 | } 22 | 23 | &-link { 24 | color: $blue-light; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/sass/components/_dev.scss: -------------------------------------------------------------------------------- 1 | $block: 'dev'; 2 | 3 | .#{$block} { 4 | &-list { 5 | @media only screen and (min-width: $sm) and (max-width: 480px) { 6 | margin: 0 10px; 7 | } 8 | 9 | @media only screen and (min-width: $md) and (max-width: 1024px) { 10 | margin: 0 10px; 11 | } 12 | 13 | @media only screen and (min-width: $lg) { 14 | margin: 0 150px; 15 | } 16 | 17 | .#{$block}-card { 18 | .skill-tag { 19 | margin: 0 2px; 20 | } 21 | 22 | .image { 23 | background-color: $black-odd; 24 | background-repeat: no-repeat; 25 | background-size: cover; 26 | background-position: top; 27 | height: 300px; 28 | } 29 | 30 | .title { 31 | font-size: 20px; 32 | font-weight: 800; 33 | } 34 | 35 | .description { 36 | font-size: 14px; 37 | font-weight: 300; 38 | } 39 | } 40 | } 41 | } 42 | 43 | .App { 44 | text-align: center; 45 | } 46 | 47 | .App-logo { 48 | animation: App-logo-spin infinite 20s linear; 49 | height: 40vmin; 50 | pointer-events: none; 51 | } 52 | 53 | .App-header { 54 | background-color: #282c34; 55 | min-height: 100vh; 56 | display: flex; 57 | flex-direction: column; 58 | align-items: center; 59 | justify-content: center; 60 | font-size: calc(10px + 2vmin); 61 | color: white; 62 | } 63 | 64 | .App-link { 65 | color: #61dafb; 66 | } 67 | 68 | .dev-list { 69 | 70 | @media only screen and (min-width: 320px) and (max-width: 480px) { 71 | margin: 0 10px; 72 | } 73 | 74 | @media only screen and (min-width: 768px) and (max-width: 1024px) { 75 | margin: 0 10px; 76 | } 77 | 78 | @media only screen and (min-width: 1025px) { 79 | margin: 0 150px; 80 | } 81 | 82 | .dev-card { 83 | .skill-tag { 84 | margin: 0 2px; 85 | } 86 | 87 | .image { 88 | background-color: #212529; 89 | background-repeat: no-repeat; 90 | background-size: cover; 91 | background-position: top; 92 | height: 300px; 93 | filter: grayscale(100%); 94 | -webkit-filter: grayscale(100%); 95 | -webkit-transition: all .8s ease-in-out; 96 | 97 | &:hover { 98 | filter: grayscale(0%); 99 | -webkit-filter: grayscale(0%); 100 | } 101 | } 102 | 103 | .title { 104 | font-size: 20px; 105 | font-weight: 800; 106 | } 107 | 108 | .description { 109 | font-size: 14px; 110 | font-weight: 300; 111 | } 112 | 113 | .icons { 114 | display: inline; 115 | 116 | .link { 117 | color: #212529; 118 | text-decoration: none; 119 | 120 | &:hover { 121 | color: #747474; 122 | } 123 | 124 | .icon { 125 | font-size: 20px; 126 | margin: 0 2px; 127 | } 128 | } 129 | } 130 | } 131 | } 132 | 133 | @keyframes App-logo-spin { 134 | from { 135 | transform: rotate(0deg); 136 | } 137 | to { 138 | transform: rotate(360deg); 139 | } 140 | } 141 | 142 | @keyframes colorize { 143 | 0% { -webkit-filter: grayscale(100%); filter: grayscale(100%); } 144 | 25% { -webkit-filter: grayscale(75%); filter: grayscale(75%); } 145 | 50% { -webkit-filter: grayscale(50%); filter: grayscale(50%); } 146 | 75% { -webkit-filter: grayscale(25%); filter: grayscale(25%); } 147 | 100% { -webkit-filter: grayscale(0%); filter: grayscale(0%); } 148 | } 149 | 150 | -------------------------------------------------------------------------------- /src/sass/components/index.scss: -------------------------------------------------------------------------------- 1 | @import 'app'; 2 | @import 'dev'; 3 | -------------------------------------------------------------------------------- /src/sass/helpers/_animations.scss: -------------------------------------------------------------------------------- 1 | @keyframes App-logo-spin { 2 | from { 3 | transform: rotate(0deg); 4 | } 5 | to { 6 | transform: rotate(360deg); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/sass/helpers/index.scss: -------------------------------------------------------------------------------- 1 | @import 'animations' 2 | -------------------------------------------------------------------------------- /src/sass/index.scss: -------------------------------------------------------------------------------- 1 | @import './base'; 2 | @import './components'; 3 | @import './helpers'; 4 | -------------------------------------------------------------------------------- /src/setupTests.js: -------------------------------------------------------------------------------- 1 | import { configure } from 'enzyme'; 2 | import Adapter from 'enzyme-adapter-react-16'; 3 | 4 | configure({ adapter: new Adapter() }); 5 | -------------------------------------------------------------------------------- /src/utils/data.js: -------------------------------------------------------------------------------- 1 | export const coder1 = { 2 | name: "bob", 3 | initials: "BOB", 4 | summary: "dev", 5 | image: "", 6 | skills: "d,e,v", 7 | links: [], 8 | } 9 | 10 | export const coder2 = { 11 | name: "bill", 12 | initials: "BILL", 13 | summary: "evl", 14 | image: "", 15 | skills: "e,v,l", 16 | links: [], 17 | } 18 | 19 | export const coder3 = { 20 | name: "bobby", 21 | initials: "BOBBY", 22 | summary: "oper", 23 | image: "", 24 | skills: "o,p,e,r", 25 | links: [], 26 | } -------------------------------------------------------------------------------- /src/utils/index.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * TODO: make an stronger regex 4 | * 5 | * @param {string} word 6 | * @returns {number} -1 is the string is empty, 0 if the string is not a URL that starts 7 | * with http|https and 1 is is valid URL. 8 | */ 9 | export const checkUrl = word => { 10 | return (!word) ? -1 11 | : (/^(http|https|ftp)/.test(word)) ? 1 12 | : 0 13 | } 14 | 15 | /** 16 | * Check if the object is empty. 17 | * @param {object} obj* 18 | * @returns {boolean} true if the object is empty, false if not. 19 | */ 20 | export const isEmptyObject = obj => 21 | (Object.entries(obj).length === 0 && obj.constructor === Object) 22 | 23 | /** 24 | * Search for a property inside an object. 25 | * 26 | * @param {string} dflt the value we set if the object property is undefined or null. 27 | * @param {*} c the property we're searching for. 28 | * @param {*} obj the object where we want to search. 29 | * 30 | * @returns {defaultValue | obj[criteria]} the default value we passed or the property value we're searching for. 31 | */ 32 | export const pathOr = (defaultValue = '', criteria = '', obj) => 33 | obj[criteria] || defaultValue 34 | 35 | /** 36 | * Generate a random number. 37 | * @returns {number} the random number. 38 | */ 39 | export const randomize = () => 40 | 0.5 - Math.random() 41 | 42 | /** 43 | * Sort an array randomly. 44 | * 45 | * @param {*} data the array of data. 46 | */ 47 | export const shuffle = data => 48 | data.sort(randomize) 49 | --------------------------------------------------------------------------------