Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
renatolinsdigital committed Sep 3, 2024
0 parents commit b2f4819
Show file tree
Hide file tree
Showing 140 changed files with 9,111 additions and 0 deletions.
20 changes: 20 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
'plugin:prettier/recommended'
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh', 'prettier'],
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true }
],
'prettier/prettier': 'error'
}
};
29 changes: 29 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Project Files
TODO.txt

# Editor directories and files
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

# Local Netlify folder
.netlify
Empty file added .gitkeep
Empty file.
11 changes: 11 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"semi": true,
"tabWidth": 2,
"printWidth": 80,
"useTabs": false,
"singleQuote": true,
"bracketSpacing": true,
"arrowParens": "avoid",
"trailingComma": "none",
"bracketSameLine": true
}
7 changes: 7 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll": "explicit"
}
}
99 changes: 99 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# DigitalBookStore by Renato Lins

A simple store app made with React.

## How the application looks like

![Home](prints/home.png)

![Cart](prints/cart.png)

![Success](prints/success.png)

## Commands

- Formatting: `yarn format`
- Running the project: `yarn dev`
- Building the project: `yarn build`
- Manual deploy (Netlify): `netlify deploy --prod --dir=dist`

## Main Technologies used

- React
- Typescript
- Sass (global styling)
- Redux (w/ Redux Toolkit)
- Styled components (with Javascript syntax)

## Key features/characteristics

- Responsive
- Theme-based styling
- Routing is fully implemented
- Codebase is fully typed with TypeScript
- Data fetching and parsing from a real API
- Clear separation of domain-specific components from shared components
- Redux Toolkit configured with both synchronous and asynchronous reducers
- Shared folder with presentation components functioning as a design system
- Everything is a component, either a React component or a styled component
- Project is configured for absolute imports (no long and confusing import paths)

## Top-Level Folders

- **global-styles**: Resets and sets core styling for the entire application.

- **theme**: Manages themeable styling for the app, supporting features like dark mode or user-selectable themes.

- **shared**: Code used across the app, not tied to any domain. This could evolve into a private/internal library for other projects. Contains shared components, models, icons, hooks, etc.

- **domain**: The main module of the application. If the app expands, similar folders (e.g., "users," "payment") will be added for each new domain, containing relevant components, pages, icons, and hooks. Domains can have multiple sub-routes like "users/registration" or "users/reports".

## Images

This application avoids using a separate assets folder to enhance scalability. The `<Image>` component understands this separation, allowing us to utilize domain-specific, shared, and external images seamlessly.

## Responsiveness

The application uses a custom hook called useResponsiveBooleans to manage responsive behavior. This hook combines the application's pre-defined breakpoints with the mobile-detect library, providing size information through JavaScript instead of media queries or CSS mixins. This approach has several benefits:

- Mobile optimization: Ideal for mobile-focused apps or those being ported to mobile.
- Consistent sizing: Designers and developers are encouraged to use the same terminology for sizing.
- No CSS changes: Components handle values from a custom hook, eliminating the need to modify CSS.
- Easier development: Sizes are mapped to booleans, allowing developers to focus on component behavior rather than figuring out sizes.

Easy usage: Access hook values like this:

```javascript
return {
isSmall, // In mobile mode or small screen on desktop - Width < 960px
isSmaller, // Width < 768px or small screen on desktop
isSuperSmall, // Width or height <= 480px
isInMobileMode, // Device detected as mobile or tablet
isDesktopBigScreen, // Not in mobile mode and screen size >= 1280px
isDesktopSmallScreen // Not in mobile mode and screen size < 1280px
};
```

Then we just pass values to our components already. For example:

```javascript
<MyComponent maxWidth={isSuperSmall ? 255 : 290} />
```

## Tests

Despite a few testing files are present, tests are not implemented yet.

## Improvement possibilities (Out of scope)

- Translation
- A main menu
- Breadcrumbs
- Dark/Light mode toggling
- Authentication/Authorization
- Integration with an actual store
- Infinite Scroll and/or Pagination
- Better page transition animations
- UI feedback using Toastr messages
- A more robust error handling approach
- etc
1 change: 1 addition & 0 deletions _redirects
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/* /index.html 200
43 changes: 43 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta
name="description"
content="DigitalBookStore - The best experience in finding the best books" />
<meta name="keywords" content="books, knowledge, learning" />
<meta name="author" content="Renato Lins" />
<link rel="icon" href="/favicon.ico" />

<title>DigitalBookStore</title>
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website" />
<meta property="og:url" content="https://www.digitalbookstore.com" />
<meta property="og:title" content="DigitalBookStore" />
<meta
property="og:description"
content="The best experience in finding the best books" />
<meta
property="og:image"
content="https://www.digitalbookstore.com/og-image.jpg" />

<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:url" content="https://www.digitalbookstore.com" />
<meta property="twitter:title" content="DigitalBookStore" />
<meta
property="twitter:description"
content="The best experience in finding the best books" />
<meta
property="twitter:image"
content="https://www.digitalbookstore.com/twitter-image.jpg" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
10 changes: 10 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// jest.config.js
export default {
preset: 'ts-jest',
testEnvironment: 'jest-environment-jsdom',
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
testMatch: ['**/?(*.)+(test).[tj]s?(x)'],
transform: {
'^.+\\.(ts|tsx)$': 'ts-jest'
}
};
48 changes: 48 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"name": "digitalbookstore",
"private": true,
"type": "module",
"version": "1.0.0",
"scripts": {
"dev": "vite",
"test": "jest",
"preview": "vite preview",
"format": "prettier --write .",
"build": "tsc -b && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0 --fix"
},
"dependencies": {
"-": "^0.0.1",
"@reduxjs/toolkit": "^2.2.7",
"@types/node-sass": "^4.11.7",
"axios": "^1.7.4",
"mobile-detect": "^1.4.5",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-redux": "^9.1.2",
"styled-components": "^6.1.12"
},
"devDependencies": {
"@testing-library/dom": "^10.4.0",
"@testing-library/jest-dom": "^6.4.8",
"@testing-library/react": "^16.0.0",
"@testing-library/react-hooks": "^8.0.1",
"@types/jest": "^29.5.12",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@typescript-eslint/eslint-plugin": "^7.13.1",
"@typescript-eslint/parser": "^7.13.1",
"@vitejs/plugin-react": "^4.3.1",
"eslint": "^8.57.0",
"eslint-plugin-react-hooks": "^4.6.2",
"eslint-plugin-react-refresh": "^0.4.7",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"prettier": "^3.3.3",
"react-router-dom": "^6.26.1",
"sass": "^1.77.8",
"ts-jest": "^29.2.4",
"typescript": "^5.2.2",
"vite": "^5.4.0"
}
}
Binary file added prints/cart.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added prints/home.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added prints/success.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { defaultTheme } from './theme';
import { BrowserRouter } from 'react-router-dom';
import globalStyles from './global-styles/index.module.scss';
import { ThemeProvider, createGlobalStyle } from 'styled-components';

import {
AppBody,
AppFooter,
AppHeader,
AppContainerStyled
} from './domain/components';

const GlobalStyles = createGlobalStyle`${globalStyles}`;
function App() {
return (
<>
<ThemeProvider theme={defaultTheme}>
<GlobalStyles />
<AppContainerStyled>
<BrowserRouter>
<AppHeader />
<AppBody />
<AppFooter />
</BrowserRouter>
</AppContainerStyled>
</ThemeProvider>
</>
);
}

export default App;
Binary file added src/assets/fonts/OpenSans-Bold.ttf
Binary file not shown.
Binary file added src/assets/fonts/OpenSans-Regular.ttf
Binary file not shown.
Binary file added src/assets/fonts/OpenSans-SemiBold.ttf
Binary file not shown.
46 changes: 46 additions & 0 deletions src/data/books.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"products": [
{
"id": 1,
"price": 9.99,
"title": "The First Book",
"image": "src/data/images/book1.png",
"downloadUrl": "src/data/books/book1.pdf"
},
{
"id": 2,
"price": 12.59,
"title": "The Second Book",
"image": "src/data/images/book2.png",
"downloadUrl": "src/data/books/book2.pdf"
},
{
"id": 3,
"price": 29.0,
"title": "The Third Book",
"image": "src/data/images/book3.png",
"downloadUrl": "src/data/books/book3.pdf"
},
{
"id": 4,
"price": 19.5,
"title": "The Fourth Book",
"image": "src/data/images/book4.png",
"downloadUrl": "src/data/books/book4.pdf"
},
{
"id": 5,
"price": 22.5,
"title": "The Fifth Book",
"image": "src/data/images/book5.png",
"downloadUrl": "src/data/books/book5.pdf"
},
{
"id": 6,
"price": 16.9,
"title": "The Sixth Book",
"image": "src/data/images/book6.png",
"downloadUrl": "src/data/books/book6.pdf"
}
]
}
Binary file added src/data/books/book1.pdf
Binary file not shown.
Binary file added src/data/books/book2.pdf
Binary file not shown.
Binary file added src/data/books/book3.pdf
Binary file not shown.
Binary file added src/data/books/book4.pdf
Binary file not shown.
Binary file added src/data/books/book5.pdf
Binary file not shown.
Binary file added src/data/books/book6.pdf
Binary file not shown.
Binary file added src/data/images/book1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/data/images/book2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/data/images/book3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/data/images/book4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/data/images/book5.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/data/images/book6.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions src/domain/components/AppBody/AppBody.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { BoxStyled } from '@/shared/components';
import { Route, Routes } from 'react-router-dom';
import { Cart, Home, NotFound, Success } from '@/domain/pages';

const AppBody = () => {
return (
<BoxStyled $backgroundColorName="secondary" className="outlet-container">
<Routes>
<Route path="/" element={<Home />} />
<Route path="*" element={<NotFound />} />
<Route path="/cart" element={<Cart />} />
<Route path="/success" element={<Success />} />
</Routes>
</BoxStyled>
);
};

export default AppBody;
19 changes: 19 additions & 0 deletions src/domain/components/AppContainerStyled/AppContainerStyled.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import styled, { CSSObject } from 'styled-components';

const AppContainerStyled = styled.div.attrs({
className: 'AppContainerStyled'
})(({ theme }): CSSObject => {
const { colors } = theme;

return {
width: '100%',
height: '100%',
display: 'grid',
minHeight: '100vh',
color: colors.dark,
backgroundColor: colors.white,
gridAutoRows: 'min-content 1fr min-content'
};
});

export default AppContainerStyled;
Loading

0 comments on commit b2f4819

Please sign in to comment.