Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions arts-gallery/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# production
/build

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

npm-debug.log*
yarn-debug.log*
yarn-error.log*
143 changes: 65 additions & 78 deletions arts-gallery/README.md
Original file line number Diff line number Diff line change
@@ -1,104 +1,91 @@
# ArtsGallery
# Art Gallery

You will be creating a full-stack application to save paintings into a gallery by uploading them and saving them into a database. In order to do this you will be using MongoDB with the [Mongoose ODM](http://mongoosejs.com/). Your front end will display views created from data in the database. You will use [ReactJS](https://facebook.github.io/react/) for that, and will serve your application with a [NodeJS](https://nodejs.org/) web server, using [ExpressJS](https://expressjs.com/).
Full-stack application to save paintings into a gallery by uploading them and saving them into a database.

Please work on the following features **in order**, moving on to the next feature only after the one you are working on is complete. **Please commit WORKING code early and often**. In addition, after each step, please follow the guidelines for a commit message.
## Tech Stack

### Part 1 - Paintings Gallery
**Client:** React

1. **As a user**, I want to be able to view the paintings I have in my gallery. If no paintings are present in the database, I will have to see a message indicating that `No paintings in Gallery` and a button to upload new ones.
**Server:** Node, Express, MongoDB, Cloudinary, Multer

To implement this user story, you should:
## API Reference

- Write an ExpressJS web server that listens to request on port `8000`.
- Run this command a brand new React App in a folder named `client`. Then navigate to it.
```
npx create-react-app client
cd client/
```
- You may want to use [React Router](https://reactrouter.com/) or [Conditional Rendering](https://www.reactjs.org/docs/conditional-rendering.html) to navigate between components.
- Write a script that would add the dummy data to your database when `npm run seed-database` is run from the command line. Add this command to the `package.json` to be able to run it with `npm`. When you have this working, run the command so that your database is populated.
\_Note: Create a Painting Schema under `server/models/Painting.js`. It should have these following attributes:
- `id`: Number
- `artist`: String _(for the author field)_
- `name`: String
- `year`: Number
- Complete the route `/api/paintings` in `server/routes/paintings.routes.js` so that requests to this route are responded to with the data for all the paintings, retrieved from the database.
- You can use the `dummy_data.js` for your front end views. Then, you can refactor your front end to retrieve seed data from the server rather than using the dummy data.
- Render each painting in a `Card` containing the image, the name, the artist, and the date.
- **WHEN COMPLETE AND WORKING, make a commit that says `Part 1 Complete`**
#### Get all paintings

### Part 2 - Create new Paintings
```http
GET /api/v1/paintings
```

1. **As a user**, I want to be able to create new Paintings and save them in the database. First, make this feature work with a simple form where the user can manually input:
#### Get ONE painting

- Name
- Artist
- Year
- Painting url
For consistency, use real data from the internet when you test your application.
```http
GET /api/v1/paintings/${id}
```

2. **As a user**, I want to be able create new Paintings by uploading images from my local machine.
For this, you should:
| Parameter | Type | Description |
| :-------- | :------- | :-------------------------------- |
| `_id` | `ObjectID` | **Required**. Id of painting to fetch |

- Add an input of type `file` to your form where user can upload images
- Use `FormData` to send a request including data and files
- Use [multer](https://www.npmjs.com/package/multer) to handle requests including files
- Use [Cloudinary](https://cloudinary.com/) to store images in the cloud and generate urls
- Save the Painting with the data from the inputs and the url generated by Cloudinary

- **WHEN COMPLETE AND WORKING, make a commit that says `Part 2 Complete`**

### Part 3 - Edit Existing Paintings
#### Create painting

1. **As a user**, I want to update existing paintings in the database.
```http
POST /api/v1/paintings
```

- With every Painting Card, there should be an `Edit` button.
- When the user clicks on `Edit`, a new `Modal` should be rendered
- The `Modal` will contain a **prefilled** form with the data of the selected painting
- The user can click on `Cancel` to close the Modal
- The user can update the data and click on `save`
- The modal will be closed and the data of the painting will be updated in the `PaitningList` component
#### Update painting

- **WHEN COMPLETE AND WORKING, make a commit that says `Part 3 Complete`**
```http
GET /api/v1/paintings/${id}
```

### Part 4 - Delete Painting
| Parameter | Type | Description |
| :-------- | :------- | :-------------------------------- |
| `_id` | `ObjectID` | **Required**. Id of painting to update |

1. **As a user**, I want to be able to delete existing paintings from the database
#### Delete painting

- Each painting card will contain a `Delete` button
- When the user clicks on the `Delete` button, a `Modal` will be rendered with 2 options: `Confirm` and `Cancel`
- Clicking on `Confirm` will delete the painting and close the modal
- The painting will no longuer exist in the `PaintingList` component
```http
GET /api/paintings/${id}
```

- **WHEN COMPLETE AND WORKING, make a commit that says `Part 4 Complete`**
| Parameter | Type | Description |
| :-------- | :------- | :-------------------------------- |
| `_id` | `ObjectID` | **Required**. Id of painting to delete |

### API Structure
## Installation

> **Pro tip:** Install and use [Postman](https://www.getpostman.com/) to test your API routes for this section
Clone the project into your local machine

Using the existing code provided in `server/`, follow the steps below to build out a Paintings API:
```bash
git clone https://github.com/WaelChettaoui/art-gallery.git
cd art-gallery
```
⚠ BEFORE RUNNING THE PROJECT, YOU MUST CONFIGURE YOUR .env FILE ⚠

| URL | HTTP Verb | Request Body | Result |
| :----------------: | :-------: | :----------: | :--------------------------------------------------------------------: |
| /api/paintings | GET | empty | Return JSON of all Paintings |
| /api/paintings | POST | JSON | Create new Painting and return JSON of created Painting |
| /api/paintings/:id | DELETE | empty | Return JSON of single Painting with matching `number` |
| /api/paintings/:id | PUT | FormData | Update Painting with matching `id` and return JSON of updated Painting |
Switch into the server folder and install the dependencies

## Available Resources
```bash
cd server
npm i
```

- [Stack Overflow](http://stackoverflow.com/)
- [MDN](https://developer.mozilla.org/)
- [ExpressJS Docs](https://expressjs.com/)
- [Body Parser Middleware Docs](https://github.com/expressjs/body-parser)
- [Mongo Docs](https://www.mongodb.com/)
- [Mongoose ODM Docs](http://mongoosejs.com/)
- [Cloudinary API](https://cloudinary.com/documentation/node_integration)
- [ReactJS Docs](https://facebook.github.io/react/)
- [React Router Docs](https://github.com/ReactTraining/react-router/tree/master/docs)
- [NodeJS Docs](https://nodejs.org/)
- [Academind Node-Multer](https://www.youtube.com/watch?v=srPXMt1Q0nY&ab_channel=Academind) to learn how to handle uploaded images in Node
- [Academind React Image Upload](https://www.youtube.com/watch?v=XeiOnkEI7XI&ab_channel=Academind) to learn how to upload images in React
- [Postman](https://www.getpostman.com/)
- Docs for any npm packages you might use
Switch into the client folder and install the dependencies

```bash
cd ../client
npm i
```

Run the project
```bash
cd ..
npm run dev
```

## Authors

- [@mohamedazizkallel](https://github.com/mohamedazizkallel)
- [@sfareya](https://github.com/sfareya)
- [@WaelChettaoui](https://github.com/WaelChettaoui)
23 changes: 23 additions & 0 deletions arts-gallery/client/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# 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*
42 changes: 42 additions & 0 deletions arts-gallery/client/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "gallery",
"version": "0.1.0",
"private": true,
"dependencies": {
"@material-ui/core": "^4.12.3",
"@material-ui/icons": "^4.11.2",
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/react": "^12.1.2",
"@testing-library/user-event": "^13.5.0",
"axios": "^0.24.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "^5.3.0",
"react-scripts": "5.0.0",
"web-vitals": "^2.1.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
47 changes: 47 additions & 0 deletions arts-gallery/client/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />

<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Abril+Fatface&display=swap" rel="stylesheet">
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.

Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>Art Gallery</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.

You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.

To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
3 changes: 3 additions & 0 deletions arts-gallery/client/public/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
38 changes: 38 additions & 0 deletions arts-gallery/client/src/App.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
.App {
text-align: center;
}

.App-logo {
height: 40vmin;
pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}

.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}

.App-link {
color: #61dafb;
}

@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
25 changes: 25 additions & 0 deletions arts-gallery/client/src/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import './App.css'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'

// Importing components
import Gallery from './components/gallery/Gallery'
import AddPainting from './components/addPainting/AddPainting'
import EditPainting from './components/editPainting/editPainting'
import Navbar from './components/navbar/Navbar'

function App() {
return (
<Router>
<div className='container'>
<Navbar />
<Switch>
<Route exact path='/' component={Gallery} />
<Route path='/add' component={AddPainting} />
<Route path='/:id' component={EditPainting} />
</Switch>
</div>
</Router>
)
}

export default App
8 changes: 8 additions & 0 deletions arts-gallery/client/src/App.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { render, screen } from '@testing-library/react'
import App from './App'

test('renders learn react link', () => {
render(<App />)
const linkElement = screen.getByText(/learn react/i)
expect(linkElement).toBeInTheDocument()
})
Loading