# Sprint 1

---
#### The project :sparkles:
An e-commerce style site to search and compare seed varieties and prices.
---
#### MVP :star2:
* A mobile first approach
* Landing page.
* Burger menu.
* All seeds page with working filters.
* Dynamic routes to product pages.
* Basic styling to be able to present.
---
#### Scrum Facilitator :bookmark_tabs:
* Estimate: 28points Actual:32 points
* Regular meetings with product owner/discord.
* Stand-ups (stand-up next week!).
* Frequently update project board on github to give people a sense of completing tasks and also track velocity.
* Make sure issues are broken down into smaller tasks.
* Made some new issues for sprint 2.
* Managed to stay motivated as a team.
---
#### Devops
- Project setup took a long time due to the oldness of my laptop and waiting for npm to finish installing everything. To prevent losing out on time, we decided to carry on the project setup on another laptop :weary: Due to difference in our npm and node versions this caused chaos with all of our `package-lock.json` files conflicting :exploding_head: And we decided to make a new repository from scratch...Lusan 2.0 :seedling:
---
- The Vercel logs have been helpful and informative of specifically what file the error is in :face_with_monocle:
---
- 
---
#### Quality Assurance
Setting up a project commit message template:
1. Create your desired commit template in a file inside the project (I put ours in the root)
---
2. Run these commands in the terminal or put them in a script file
```bash
#! /bin/sh
# make vscode the default editor for commit messages in this repo
git config --local core.editor "code -w"
# configure commit message template to commit-message file in this repo
git config commit.template .commit-message
```
---
3. Next time you commit, just type `git commit` in the terminal and the editor will open your template. Close the file to save the commit
---
Our template:
```
# Title: Summary, imperative, start upper case, no period
# No more than 50 chars. #### 50 chars is here: #
# Body: Explain what this commit does using bullet points (use - or *)
# Wrap at 72 chars. ################################## which is here: #
# Relates or closes issue number (i.e Relates #3):
# Include Co-authored-by for all contributors. Format:
# Co-authored-by: name <user@users.noreply.github.com>
```
---
File naming conventions:
- Important to agree on and adhere to from the get go!
- React and Styled Components: PascalCase
- Next pages: lowercase, separate words with hyphen (the React components declared inside of the files are PascalCased)
---
#### UX/UI
- Positive feedback on Figma prototype design in testing
- Using `styled-components` as we wanted to create our own unique components
- UX and styling is a work in progress, prioritised building out key functionalities in the first sprint
- In sprint two we will fine-tune CSS and styling on existing pages and `styled-components`
---
#### Bugs & Learning :bug::thinking_face:
---
Package lock
- Before starting a project, check that everyone on your team is on the same npm and node versions by typing `npm --version` in your terminal and look at the [npm-version Docs](https://docs.npmjs.com/cli/v8/commands/npm-version)
---
- A screenshot of the madness of conflicting package-lock.json files

---
#### Dynamic routes
* Creating dynamic routes in next without a back end === very tricky.
* Using react router rather than static paths, due to no db queries.
* Create `products` folder inside pages with a `[variety].js` file.
* Next will generate the routes for you `local:host3000/products/{anything here}`
---
#### Issues
* Making the content dynamic on the page.
---
```jsx=
const ProductPages = () => {
const router = useRouter();
const [variety, setVariety] = useState(null);
const [object, setObject] = useState(null);
useEffect(() => {
if (router.isReady) {
setVariety(router.query.variety);
}
}, [router]);
```
---
```jsx=
const capitalisedVariety =
variety && variety.replace(/^\w/, (c) => c.toUpperCase());
useEffect(() => {
setObject(findContent(capitalisedVariety));
}, [variety, capitalisedVariety]);
```
---
```jsx= function findContent(capitalisedVariety) {
// find variety
const foundObject = products.find((productObject) => {
return productObject.variety === capitalisedVariety;
});
return foundObject;
// find index of this variety
}
```
---
```jsx=
return (
<StyledProductPage>
<div className="flex-row">
<img src={object && object.imgs[0]}></img>
etc....
```
---
* Using Next Images can be tricky, if you are using a url you can get an error about unconfigured host in your next.config file

[Next-image unconfigured host](https://nextjs.org/docs/messages/next-image-unconfigured-host)
---
* If you have the image as a jpg or png inside your repo, then the relative pathway in the Image src is as follows :point_down: Remember the `/`

---
Filtering issues
-
So many states...
```jsx=
export default function AllSeeds() {
const [category, setCategory] = useState("All");
const [searchTerm, setSearchTerm] = useState(null);
// type states
const [organic, setOrganic] = useState(false);
const [openPollinated, setOpenPollinated] = useState(false);
const [hybrid, setHybrid] = useState(false);
// climate states
const [sunny, setSunny] = useState(false);
const [shady, setShady] = useState(false);
const [humid, setHumid] = useState(false);
// water states
const [lotsOfWater, setLotsOfWater] = useState(false);
const [dry, setDry] = useState(false);
// soil states
const [clay, setClay] = useState(false);
const [drained, setDrained] = useState(false);
const [chalky, setChalkey] = useState(false);
const [peaty, setPeaty] = useState(false);
const [sandy, setSandy] = useState(false);
// price states
const [min, setMin] = useState(0);
const [max, setMax] = useState(10);
```
---
So many filters...
```jsx=
products &&
products
.filter((product) => (organic ? product.type.organic : product))
.filter((product) =>
openPollinated ? product.type.openPollinated : product
)
.filter((product) => (hybrid ? product.type.hybrid : product))
.filter((product) => (sunny ? product.climate.sunny : product))
.filter((product) => (shady ? product.climate.shady : product))
.filter((product) => (humid ? product.climate.humid : product))
.filter((product) => (lotsOfWater ? product.water.water : product))
.filter((product) => (dry ? product.water.dry : product))
.filter((product) => (clay ? product.soil.clay : product))
.filter((product) => (drained ? product.soil.drained : product))
.filter((product) => (chalky ? product.soil.chalky : product))
.filter((product) => (peaty ? product.soil.peaty : product))
.filter((product) => (sandy ? product.soil.sandy : product))
```
---
Is there a better way? :thinking_face: tbc...
```javascript=
// the user preference (checboxes ticked)
const typeConditions = {
organic: false,
openPollinated: true,
hybrid: true,
};
// the product properties
const productType = {
organic: true,
openPollinated: true,
hybrid: true,
};
const keys = Object.keys(typeConditions);
const every = keys.every((key) => typeConditions[key] === productType[key]);
console.log(every); // false
```
---
Burger menu
- Responsive CSS means the navbar collapses in mobile view and is instead viewable by clicking the burger menu
- Created a responsive burger menu
- Used styled div and CSS animations to create make the burger menu turn into a X
---
- 
---
- 
---
````javascript
export default function Burger() {
const [open, setOpen] = React.useState(false);
return (
<div>
<StyledBurger
open={open}
onClick={() => {
setOpen(!open);
}}
>
<div />
<div />
<div />
</StyledBurger>
<LeftNav open={open}></LeftNav>
</div>
````
```javascript=
const StyledBurger = styled.div`
&:nth-child(1) {
transform: ${({ open }) => (open ? "rotate(45deg)" : "rotate(0)")};
}
&:nth-child(2) {
opacity: ${({ open }) => (open ? 0 : 1)};
transform: ${({ open }) =>
open ? "translateX(100%)" : "translateX(0)"};
}
&:nth-child(3) {
transform: ${({ open }) => (open ? "rotate(-45deg)" : "rotate(0)")};
}
}
}
`;
```
---
Realised the menu persists when navigating to new page as the only Layout component is not re-rendered on the new route and the state persists
---
Explored using the next `useRouter` functionality to reset the state, which would close the burger menu.
Decided it was not a priority for sprint 1 and will revisit in sprint 2.
---
```javascript=
import { useEffect } from 'react'
import { useRouter } from 'next/router'
export default function MyApp({ Component, pageProps }) {
const router = useRouter()
useEffect(() => {
const handleRouteChange = (url, { shallow }) => {
console.log(
`App is changing to ${url} ${
shallow ? 'with' : 'without'
} shallow routing`
)
}
router.events.on('routeChangeStart', handleRouteChange)
// If the component is unmounted, unsubscribe
// from the event with the `off` method:
return () => {
router.events.off('routeChangeStart', handleRouteChange)
}
}, [])
```
---
[Demo](https://lusan-tfb-ltfb.vercel.app/) :sparkles:
{"metaMigratedAt":"2023-06-16T22:02:43.828Z","metaMigratedFrom":"Content","title":"Sprint 1","breaks":true,"contributors":"[{\"id\":\"5fc58879-82a7-42a5-adb7-d717c9b3063b\",\"add\":2399,\"del\":135},{\"id\":\"3934dd6c-8588-4d47-a23b-ba8c96da8ea7\",\"add\":3930,\"del\":83},{\"id\":\"ae3532b1-4610-4f25-89ec-b00c8da7a54b\",\"add\":1514,\"del\":126},{\"id\":\"e5b68a4f-393a-493d-b3f4-835497a37486\",\"add\":3495,\"del\":1025}]"}