Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
F
Full-Stack
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
1
Merge Requests
1
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Нұрасыл Қайратұлы
Full-Stack
Commits
31f76dda
Commit
31f76dda
authored
Jul 16, 2024
by
Нұрасыл Қайратұлы
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'update_front' into 'master'
Update front See merge request
!3
parents
66ec1700
4df12fa3
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
415 additions
and
57 deletions
+415
-57
package-lock.json
Backend/package-lock.json
+36
-0
package.json
Backend/package.json
+3
-0
products.json
Backend/src/data/products.json
+14
-0
index.ts
Backend/src/index.ts
+2
-1
product.route.ts
Backend/src/routes/product.route.ts
+1
-1
yarn.lock
Backend/yarn.lock
+26
-1
.prettierrc
Frontend/.prettierrc
+7
-0
.prettierrc.cjs
Frontend/.prettierrc.cjs
+0
-7
settings.json
Frontend/.vscode/settings.json
+3
-8
package.json
Frontend/package.json
+2
-1
App.tsx
Frontend/src/App.tsx
+26
-6
ProductForm.tsx
Frontend/src/components/ProductForm/ProductForm.tsx
+92
-0
AppToolbar.tsx
Frontend/src/components/UI/AppToolbar/AppToolbar.tsx
+23
-0
NewProduct.tsx
Frontend/src/containers/NewProduct/NewProduct.tsx
+30
-0
ProductItem.tsx
Frontend/src/containers/Products/ProductItem.tsx
+39
-0
Products.tsx
Frontend/src/containers/Products/Products.tsx
+40
-0
productsSlice.ts
Frontend/src/features/productsSlice.ts
+41
-9
axiosApiClient.ts
Frontend/src/helpers/axiosApiClient.ts
+5
-0
index.css
Frontend/src/index.css
+3
-6
IProduct.ts
Frontend/src/interfaces/IProduct.ts
+6
-0
index.ts
Frontend/src/store/index.ts
+9
-2
tsconfig.json
Frontend/tsconfig.json
+4
-12
vite.config.ts
Frontend/vite.config.ts
+3
-3
No files found.
Backend/package-lock.json
View file @
31f76dda
...
@@ -9,11 +9,14 @@
...
@@ -9,11 +9,14 @@
"version"
:
"1.0.0"
,
"version"
:
"1.0.0"
,
"license"
:
"ISC"
,
"license"
:
"ISC"
,
"dependencies"
:
{
"dependencies"
:
{
"@types/cors"
:
"^2.8.17"
,
"class-transformer"
:
"^0.5.1"
,
"class-transformer"
:
"^0.5.1"
,
"class-validator"
:
"^0.14.1"
,
"class-validator"
:
"^0.14.1"
,
"cors"
:
"^2.8.5"
,
"express"
:
"^4.18.2"
,
"express"
:
"^4.18.2"
,
"reflect-metadata"
:
"^0.2.2"
,
"reflect-metadata"
:
"^0.2.2"
,
"save"
:
"^2.9.0"
,
"save"
:
"^2.9.0"
,
"save-dev"
:
"^0.0.1-security"
,
"ts-node"
:
"^10.9.1"
,
"ts-node"
:
"^10.9.1"
,
"tslib"
:
"^2.6.0"
,
"tslib"
:
"^2.6.0"
,
"typescript"
:
"^5.1.6"
,
"typescript"
:
"^5.1.6"
,
...
@@ -259,6 +262,14 @@
...
@@ -259,6 +262,14 @@
"@types/node"
:
"*"
"@types/node"
:
"*"
}
}
},
},
"node_modules/@types/cors"
:
{
"version"
:
"2.8.17"
,
"resolved"
:
"https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz"
,
"integrity"
:
"sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA=="
,
"dependencies"
:
{
"@types/node"
:
"*"
}
},
"node_modules/@types/express"
:
{
"node_modules/@types/express"
:
{
"version"
:
"4.17.17"
,
"version"
:
"4.17.17"
,
"resolved"
:
"https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz"
,
"resolved"
:
"https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz"
,
...
@@ -940,6 +951,18 @@
...
@@ -940,6 +951,18 @@
"resolved"
:
"https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz"
,
"resolved"
:
"https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz"
,
"integrity"
:
"sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
"integrity"
:
"sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
},
},
"node_modules/cors"
:
{
"version"
:
"2.8.5"
,
"resolved"
:
"https://registry.npmjs.org/cors/-/cors-2.8.5.tgz"
,
"integrity"
:
"sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g=="
,
"dependencies"
:
{
"object-assign"
:
"^4"
,
"vary"
:
"^1"
},
"engines"
:
{
"node"
:
">= 0.10"
}
},
"node_modules/create-require"
:
{
"node_modules/create-require"
:
{
"version"
:
"1.1.1"
,
"version"
:
"1.1.1"
,
"resolved"
:
"https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz"
,
"resolved"
:
"https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz"
,
...
@@ -2359,6 +2382,14 @@
...
@@ -2359,6 +2382,14 @@
"url"
:
"https://github.com/sponsors/sindresorhus"
"url"
:
"https://github.com/sponsors/sindresorhus"
}
}
},
},
"node_modules/object-assign"
:
{
"version"
:
"4.1.1"
,
"resolved"
:
"https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
,
"integrity"
:
"sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="
,
"engines"
:
{
"node"
:
">=0.10.0"
}
},
"node_modules/object-inspect"
:
{
"node_modules/object-inspect"
:
{
"version"
:
"1.12.3"
,
"version"
:
"1.12.3"
,
"resolved"
:
"https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz"
,
"resolved"
:
"https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz"
,
...
@@ -2887,6 +2918,11 @@
...
@@ -2887,6 +2918,11 @@
"mingo"
:
"^6.1.0"
"mingo"
:
"^6.1.0"
}
}
},
},
"node_modules/save-dev"
:
{
"version"
:
"0.0.1-security"
,
"resolved"
:
"https://registry.npmjs.org/save-dev/-/save-dev-0.0.1-security.tgz"
,
"integrity"
:
"sha512-k6knZTDNK8PKKbIqnvxiOveJinuw2LcQjqDoaorZWP9M5AR2EPsnpDeSbeoZZ0pHr5ze1uoaKdK8NBGQrJ34Uw=="
},
"node_modules/semver"
:
{
"node_modules/semver"
:
{
"version"
:
"7.5.4"
,
"version"
:
"7.5.4"
,
"resolved"
:
"https://registry.npmjs.org/semver/-/semver-7.5.4.tgz"
,
"resolved"
:
"https://registry.npmjs.org/semver/-/semver-7.5.4.tgz"
,
...
...
Backend/package.json
View file @
31f76dda
...
@@ -13,11 +13,14 @@
...
@@ -13,11 +13,14 @@
"author"
:
""
,
"author"
:
""
,
"license"
:
"ISC"
,
"license"
:
"ISC"
,
"dependencies"
:
{
"dependencies"
:
{
"@types/cors"
:
"^2.8.17"
,
"class-transformer"
:
"^0.5.1"
,
"class-transformer"
:
"^0.5.1"
,
"class-validator"
:
"^0.14.1"
,
"class-validator"
:
"^0.14.1"
,
"cors"
:
"^2.8.5"
,
"express"
:
"^4.18.2"
,
"express"
:
"^4.18.2"
,
"reflect-metadata"
:
"^0.2.2"
,
"reflect-metadata"
:
"^0.2.2"
,
"save"
:
"^2.9.0"
,
"save"
:
"^2.9.0"
,
"save-dev"
:
"^0.0.1-security"
,
"ts-node"
:
"^10.9.1"
,
"ts-node"
:
"^10.9.1"
,
"tslib"
:
"^2.6.0"
,
"tslib"
:
"^2.6.0"
,
"typescript"
:
"^5.1.6"
,
"typescript"
:
"^5.1.6"
,
...
...
Backend/src/data/products.json
0 → 100644
View file @
31f76dda
[
{
"id"
:
"d2d4a838-64d2-45e1-954b-ac4d744d9497"
,
"title"
:
"test"
,
"description"
:
"adsdasdadadsadad"
,
"price"
:
500000
},
{
"id"
:
"279e188c-ac70-4186-b3b1-52b9fd721e07"
,
"title"
:
"asasdasd"
,
"description"
:
"asdaddasad"
,
"price"
:
123123
}
]
\ No newline at end of file
Backend/src/index.ts
View file @
31f76dda
...
@@ -2,10 +2,11 @@ import App from './app';
...
@@ -2,10 +2,11 @@ import App from './app';
import
logger
from
'./middlewares/logger'
;
import
logger
from
'./middlewares/logger'
;
import
{
ArticleRoute
}
from
'./routes/article.route'
;
import
{
ArticleRoute
}
from
'./routes/article.route'
;
import
{
ProductRoute
}
from
'./routes/product.route'
;
import
{
ProductRoute
}
from
'./routes/product.route'
;
import
cors
from
'cors'
;
const
app
=
new
App
({
const
app
=
new
App
({
port
:
8000
,
port
:
8000
,
middlewares
:
[
logger
()],
middlewares
:
[
logger
()
,
cors
()
],
controllers
:
[
new
ArticleRoute
(),
new
ProductRoute
()],
controllers
:
[
new
ArticleRoute
(),
new
ProductRoute
()],
});
});
...
...
Backend/src/routes/product.route.ts
View file @
31f76dda
...
@@ -3,7 +3,7 @@ import { IRoute } from "@/interfaces/IRoute.interface";
...
@@ -3,7 +3,7 @@ import { IRoute } from "@/interfaces/IRoute.interface";
import
{
ProductController
}
from
"@/controllers/product.controller"
;
import
{
ProductController
}
from
"@/controllers/product.controller"
;
export
class
ProductRoute
implements
IRoute
{
export
class
ProductRoute
implements
IRoute
{
public
path
=
'/product'
;
public
path
=
'/product
s
'
;
public
router
=
Router
();
public
router
=
Router
();
private
controller
:
ProductController
;
private
controller
:
ProductController
;
...
...
Backend/yarn.lock
View file @
31f76dda
...
@@ -151,6 +151,13 @@
...
@@ -151,6 +151,13 @@
dependencies:
dependencies:
"@types/node" "*"
"@types/node" "*"
"@types/cors@^2.8.17":
version "2.8.17"
resolved "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz"
integrity sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==
dependencies:
"@types/node" "*"
"@types/express-serve-static-core@^4.17.33":
"@types/express-serve-static-core@^4.17.33":
version "4.17.35"
version "4.17.35"
resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz"
resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz"
...
@@ -560,6 +567,14 @@ cookie@0.5.0:
...
@@ -560,6 +567,14 @@ cookie@0.5.0:
resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz"
resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz"
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
cors@^2.8.5:
version "2.8.5"
resolved "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz"
integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
dependencies:
object-assign "^4"
vary "^1"
create-require@^1.1.0:
create-require@^1.1.0:
version "1.1.1"
version "1.1.1"
resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz"
resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz"
...
@@ -1452,6 +1467,11 @@ npm-run-path@^5.1.0:
...
@@ -1452,6 +1467,11 @@ npm-run-path@^5.1.0:
dependencies:
dependencies:
path-key "^4.0.0"
path-key "^4.0.0"
object-assign@^4:
version "4.1.1"
resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
object-inspect@^1.9.0:
object-inspect@^1.9.0:
version "1.12.3"
version "1.12.3"
resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz"
resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz"
...
@@ -1695,6 +1715,11 @@ safe-buffer@5.2.1:
...
@@ -1695,6 +1715,11 @@ safe-buffer@5.2.1:
resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
save-dev@^0.0.1-security:
version "0.0.1-security"
resolved "https://registry.npmjs.org/save-dev/-/save-dev-0.0.1-security.tgz"
integrity sha512-k6knZTDNK8PKKbIqnvxiOveJinuw2LcQjqDoaorZWP9M5AR2EPsnpDeSbeoZZ0pHr5ze1uoaKdK8NBGQrJ34Uw==
save@^2.9.0:
save@^2.9.0:
version "2.9.0"
version "2.9.0"
resolved "https://registry.npmjs.org/save/-/save-2.9.0.tgz"
resolved "https://registry.npmjs.org/save/-/save-2.9.0.tgz"
...
@@ -2000,7 +2025,7 @@ validator@^13.9.0:
...
@@ -2000,7 +2025,7 @@ validator@^13.9.0:
resolved "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz"
resolved "https://registry.npmjs.org/validator/-/validator-13.12.0.tgz"
integrity sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==
integrity sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==
vary@~1.1.2:
vary@
^1, vary@
~1.1.2:
version "1.1.2"
version "1.1.2"
resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz"
resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz"
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==
...
...
Frontend/.prettierrc
0 → 100644
View file @
31f76dda
{
"tabWidth": 2,
"singleQuote": true,
"trailingComma": "es5",
"printWidth": 100,
"useTabs": false
}
Frontend/.prettierrc.cjs
deleted
100644 → 0
View file @
66ec1700
module.exports = {
tabWidth: 2,
singleQuote: true,
trailingComma: 'es5',
printWidth: 100,
useTabs: false,
};
Frontend/.vscode/settings.json
View file @
31f76dda
...
@@ -10,11 +10,6 @@
...
@@ -10,11 +10,6 @@
"[typescriptreact]"
:
{
"[typescriptreact]"
:
{
"editor.formatOnSave"
:
true
"editor.formatOnSave"
:
true
},
},
"eslint.validate"
:
[
"eslint.validate"
:
[
"javascript"
,
"javascriptreact"
,
"typescript"
,
"typescriptreact"
],
"javascript"
,
"typescript.tsdk"
:
"node_modules/typescript/lib"
"javascriptreact"
,
}
"typescript"
,
"typescriptreact"
],
"typescript.tsdk"
:
"node_modules/typescript/lib"
,
}
\ No newline at end of file
Frontend/package.json
View file @
31f76dda
...
@@ -7,7 +7,8 @@
...
@@ -7,7 +7,8 @@
"dev"
:
"vite"
,
"dev"
:
"vite"
,
"build"
:
"tsc && vite build"
,
"build"
:
"tsc && vite build"
,
"lint"
:
"eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
,
"lint"
:
"eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0"
,
"preview"
:
"vite preview"
"preview"
:
"vite preview"
,
"format"
:
"prettier --write './**/*.{js,jsx,ts,tsx,css,md,json}' --config ./.prettierrc"
},
},
"dependencies"
:
{
"dependencies"
:
{
"@emotion/react"
:
"^11.11.1"
,
"@emotion/react"
:
"^11.11.1"
,
...
...
Frontend/src/App.tsx
View file @
31f76dda
const
App
=
()
=>
(
import
{
Container
,
CssBaseline
}
from
'@mui/material'
;
<>
import
{
Route
,
Routes
}
from
'react-router-dom'
;
<
header
>
Navbar will go here
</
header
>
import
{
AppToolbar
}
from
'./components/UI/AppToolbar/AppToolbar'
;
<
main
>
Main content will go here
</
main
>
import
{
Products
}
from
'./containers/Products/Products'
;
</>
import
NewProduct
from
'./containers/NewProduct/NewProduct'
;
);
function
App
()
{
return
(
<>
<
CssBaseline
/>
<
header
>
<
AppToolbar
/>
</
header
>
<
main
>
<
Container
maxWidth=
"xl"
sx=
{
{
mt
:
10
}
}
>
<
Routes
>
<
Route
path=
"/"
element=
{
<
Products
/>
}
/>
<
Route
path=
"/products/new"
element=
{
<
NewProduct
/>
}
/>
</
Routes
>
</
Container
>
</
main
>
</>
);
}
export
default
App
;
export
default
App
;
Frontend/src/components/ProductForm/ProductForm.tsx
0 → 100644
View file @
31f76dda
import
{
useState
,
ChangeEvent
,
FormEvent
}
from
'react'
;
import
{
Box
,
Button
,
Grid
,
TextField
}
from
'@mui/material'
;
import
{
ProductData
}
from
'@/containers/NewProduct/NewProduct'
;
interface
State
{
title
:
string
;
price
:
string
;
description
:
string
;
}
interface
Props
{
onSubmit
:
(
data
:
ProductData
)
=>
void
;
}
const
ProductForm
=
({
onSubmit
}:
Props
)
=>
{
const
[
state
,
setState
]
=
useState
<
State
>
({
title
:
''
,
price
:
''
,
description
:
''
,
});
const
submitFormHandler
=
(
e
:
FormEvent
<
HTMLFormElement
>
)
=>
{
e
.
preventDefault
();
const
newProduct
:
ProductData
=
{
title
:
state
.
title
,
description
:
state
.
description
,
price
:
parseInt
(
state
.
price
),
}
onSubmit
(
newProduct
)
};
const
inputChangeHandler
=
(
e
:
ChangeEvent
<
HTMLInputElement
>
)
=>
{
const
{
name
,
value
}
=
e
.
target
;
setState
((
prevState
)
=>
{
return
{
...
prevState
,
[
name
]:
value
};
});
};
return
(
<
Box
component=
{
'form'
}
autoComplete=
"off"
onSubmit=
{
submitFormHandler
}
paddingY=
{
2
}
>
<
Grid
container
direction=
"column"
spacing=
{
2
}
>
<
Grid
item
xs
>
<
TextField
fullWidth
variant=
"outlined"
id=
"title"
label=
"Title"
value=
{
state
.
title
}
onChange=
{
inputChangeHandler
}
name=
"title"
/>
</
Grid
>
<
Grid
item
xs
>
<
TextField
fullWidth
variant=
"outlined"
id=
"price"
label=
"Price"
value=
{
state
.
price
}
onChange=
{
inputChangeHandler
}
name=
"price"
/>
</
Grid
>
<
Grid
item
xs
>
<
TextField
fullWidth
multiline
rows=
{
3
}
variant=
"outlined"
id=
"description"
label=
"Description"
value=
{
state
.
description
}
onChange=
{
inputChangeHandler
}
name=
"description"
/>
</
Grid
>
<
Grid
item
xs
>
<
Button
type=
"submit"
color=
"primary"
variant=
"contained"
>
Create
</
Button
>
</
Grid
>
</
Grid
>
</
Box
>
);
};
export
default
ProductForm
;
Frontend/src/components/UI/AppToolbar/AppToolbar.tsx
0 → 100644
View file @
31f76dda
import
{
AppBar
,
Box
,
Toolbar
,
Typography
,
styled
}
from
'@mui/material'
;
import
{
Link
}
from
'react-router-dom'
;
const
StyledLink
=
styled
(
Link
)(()
=>
({
color
:
'inherit'
,
textDecoration
:
'none'
,
[
'&:hover'
]:
{
color
:
'inherit'
},
}));
export
function
AppToolbar
()
{
return
(
<>
<
AppBar
position=
"fixed"
>
<
Toolbar
>
<
Typography
variant=
"h6"
component=
{
StyledLink
}
to=
{
'/'
}
>
Computer parts shop
</
Typography
>
</
Toolbar
>
</
AppBar
>
<
Box
component=
{
Toolbar
}
marginBottom=
{
2
}
/>
</>
);
}
Frontend/src/containers/NewProduct/NewProduct.tsx
0 → 100644
View file @
31f76dda
import
{
Typography
}
from
'@mui/material'
;
import
ProductForm
from
'../../components/ProductForm/ProductForm'
;
import
{
useNavigate
}
from
'react-router-dom'
;
import
{
createProduct
}
from
'../../features/productsSlice'
;
import
{
useAppDispatch
}
from
'../../store'
;
export
interface
ProductData
{
title
:
string
;
description
:
string
;
price
:
number
;
}
const
NewProduct
=
()
=>
{
const
dispatch
=
useAppDispatch
();
const
navigate
=
useNavigate
();
const
onProductFormSubmit
=
async
(
productData
:
ProductData
)
=>
{
await
dispatch
(
createProduct
(
productData
));
navigate
(
'/'
);
};
return
(
<>
<
Typography
variant=
"h4"
>
New product
</
Typography
>
<
ProductForm
onSubmit=
{
onProductFormSubmit
}
/>
</>
);
};
export
default
NewProduct
;
Frontend/src/containers/Products/ProductItem.tsx
0 → 100644
View file @
31f76dda
import
{
Link
}
from
'react-router-dom'
;
import
{
Grid
,
Card
,
CardHeader
,
CardContent
,
CardActions
,
IconButton
,
Typography
,
}
from
'@mui/material'
;
import
{
ArrowForward
}
from
'@mui/icons-material'
;
import
{
IProduct
}
from
'@/interfaces/IProduct'
;
interface
Props
{
product
:
IProduct
;
}
export
function
ProductItem
({
product
}:
Props
)
{
const
{
title
,
price
,
id
,
description
}
=
product
;
return
(
<
Grid
item
xs=
{
12
}
sm=
{
12
}
md=
{
6
}
lg=
{
4
}
>
<
Card
sx=
{
{
minWidth
:
275
}
}
>
<
CardHeader
title=
{
title
}
/>
<
CardContent
>
<
Typography
variant=
"body2"
>
{
description
}
</
Typography
>
<
strong
style=
{
{
marginLeft
:
'10px'
}
}
>
Price:
{
price
}
KZT
</
strong
>
</
CardContent
>
<
CardActions
>
<
IconButton
component=
{
Link
}
to=
{
`/products/${id}`
}
>
<
ArrowForward
/>
</
IconButton
>
</
CardActions
>
</
Card
>
</
Grid
>
);
}
Frontend/src/containers/Products/Products.tsx
0 → 100644
View file @
31f76dda
import
{
Link
}
from
'react-router-dom'
;
import
{
Typography
,
Grid
,
Button
}
from
'@mui/material'
;
import
{
useAppDispatch
,
useAppSelector
}
from
'../../store'
;
import
{
shallowEqual
}
from
'react-redux'
;
import
{
useEffect
}
from
'react'
;
import
{
fetchProducts
}
from
'../../features/productsSlice'
;
import
{
ProductItem
}
from
'./ProductItem'
;
export
function
Products
()
{
const
dispatch
=
useAppDispatch
();
const
{
products
}
=
useAppSelector
((
state
)
=>
state
.
products
,
shallowEqual
);
useEffect
(()
=>
{
dispatch
(
fetchProducts
());
},
[
dispatch
]);
return
(
<>
<
Grid
container
direction=
"column"
spacing=
{
2
}
>
<
Grid
item
container
direction=
"row"
justifyContent=
"space-between"
alignItems=
"center"
>
<
Grid
item
>
<
Typography
variant=
"h4"
>
Products
</
Typography
>
</
Grid
>
<
Grid
item
>
<
Button
color=
"primary"
component=
{
Link
}
to=
{
'/products/new'
}
>
Add product
</
Button
>
</
Grid
>
</
Grid
>
</
Grid
>
<
Grid
item
container
direction=
"row"
spacing=
{
1
}
>
{
products
.
map
((
product
)
=>
(
<
ProductItem
key=
{
product
.
id
}
product=
{
product
}
/>
))
}
</
Grid
>
</>
);
}
Frontend/src/features/productsSlice.ts
View file @
31f76dda
import
{
createSlice
}
from
"@reduxjs/toolkit"
;
import
{
axiosApiClient
}
from
'../helpers/axiosApiClient'
;
import
{
IProduct
}
from
'../interfaces/IProduct'
;
import
{
createAsyncThunk
,
createSlice
}
from
'@reduxjs/toolkit'
;
const
initialState
=
{};
interface
State
{
products
:
IProduct
[];
error
:
Error
|
null
;
loading
:
boolean
;
}
const
productsSlice
=
createSlice
(
const
initialState
:
State
=
{
{
products
:
[],
name
:
'products'
,
error
:
null
,
initialState
,
loading
:
false
,
reducers
:
{},
};
}
)
export
const
fetchProducts
=
createAsyncThunk
(
'fetch/products'
,
async
()
=>
{
return
await
axiosApiClient
.
get
<
IProduct
[]
>
(
'/products'
).
then
((
res
)
=>
res
.
data
);
});
export
const
createProduct
=
createAsyncThunk
(
'create/products'
,
async
(
payload
:
IProduct
)
=>
{
return
await
axiosApiClient
.
post
<
IProduct
>
(
'/products'
,
payload
).
then
((
res
)
=>
res
.
data
);
});
const
productsSlice
=
createSlice
({
name
:
'products'
,
initialState
,
reducers
:
{},
extraReducers
:
(
builder
)
=>
{
builder
.
addCase
(
fetchProducts
.
fulfilled
,
(
state
,
action
)
=>
{
state
.
products
=
action
.
payload
;
state
.
loading
=
false
;
})
.
addCase
(
fetchProducts
.
rejected
,
(
state
,
action
)
=>
{
state
.
error
=
action
.
error
as
Error
;
state
.
loading
=
false
;
})
.
addCase
(
fetchProducts
.
pending
,
(
state
)
=>
{
state
.
loading
=
true
;
});
},
});
export
default
productsSlice
.
reducer
;
export
default
productsSlice
.
reducer
;
Frontend/src/helpers/axiosApiClient.ts
0 → 100644
View file @
31f76dda
import
axios
from
'axios'
;
export
const
axiosApiClient
=
axios
.
create
({
baseURL
:
'http://localhost:8000'
,
});
Frontend/src/index.css
View file @
31f76dda
body
{
body
{
margin
:
0
;
margin
:
0
;
font-family
:
-apple-system
,
BlinkMacSystemFont
,
'Segoe UI'
,
'Roboto'
,
'Oxygen'
,
font-family
:
-apple-system
,
BlinkMacSystemFont
,
'Segoe UI'
,
'Roboto'
,
'Oxygen'
,
'Ubuntu'
,
'Ubuntu'
,
'Cantarell'
,
'Fira Sans'
,
'Droid Sans'
,
'Helvetica Neue'
,
'Cantarell'
,
'Fira Sans'
,
'Droid Sans'
,
'Helvetica Neue'
,
sans-serif
;
sans-serif
;
-webkit-font-smoothing
:
antialiased
;
-webkit-font-smoothing
:
antialiased
;
-moz-osx-font-smoothing
:
grayscale
;
-moz-osx-font-smoothing
:
grayscale
;
}
}
code
{
code
{
font-family
:
source-code-pro
,
Menlo
,
Monaco
,
Consolas
,
'Courier New'
,
font-family
:
source-code-pro
,
Menlo
,
Monaco
,
Consolas
,
'Courier New'
,
monospace
;
monospace
;
}
}
Frontend/src/interfaces/IProduct.ts
0 → 100644
View file @
31f76dda
export
interface
IProduct
{
id
?:
string
;
title
:
string
;
description
:
string
;
price
:
number
;
}
Frontend/src/store/index.ts
View file @
31f76dda
import
{
configureStore
}
from
'@reduxjs/toolkit'
;
import
{
configureStore
}
from
'@reduxjs/toolkit'
;
import
productsReducer
from
'../features/productsSlice.ts'
;
import
productsReducer
from
'../features/productsSlice.ts'
;
import
{
TypedUseSelectorHook
,
useDispatch
,
useSelector
}
from
'react-redux'
;
const
store
=
configureStore
({
const
store
=
configureStore
({
reducer
:
{
reducer
:
{
products
:
productsReducer
,
products
:
productsReducer
,
}
},
})
});
type
RootState
=
ReturnType
<
typeof
store
.
getState
>
;
type
AppDispatch
=
typeof
store
.
dispatch
;
export
const
useAppDispatch
:
()
=>
AppDispatch
=
useDispatch
;
export
const
useAppSelector
:
TypedUseSelectorHook
<
RootState
>
=
useSelector
;
export
default
store
;
export
default
store
;
Frontend/tsconfig.json
View file @
31f76dda
...
@@ -2,11 +2,7 @@
...
@@ -2,11 +2,7 @@
"compilerOptions"
:
{
"compilerOptions"
:
{
"target"
:
"ES2020"
,
"target"
:
"ES2020"
,
"useDefineForClassFields"
:
true
,
"useDefineForClassFields"
:
true
,
"lib"
:
[
"lib"
:
[
"ES2020"
,
"DOM"
,
"DOM.Iterable"
],
"ES2020"
,
"DOM"
,
"DOM.Iterable"
],
"module"
:
"ESNext"
,
"module"
:
"ESNext"
,
"skipLibCheck"
:
true
,
"skipLibCheck"
:
true
,
/*
Bundler
mode
*/
/*
Bundler
mode
*/
...
@@ -22,17 +18,13 @@
...
@@ -22,17 +18,13 @@
"noUnusedParameters"
:
true
,
"noUnusedParameters"
:
true
,
"noFallthroughCasesInSwitch"
:
true
,
"noFallthroughCasesInSwitch"
:
true
,
"paths"
:
{
"paths"
:
{
"@/*"
:
[
"@/*"
:
[
"./src/*"
]
"./src/*"
]
}
}
},
},
"include"
:
[
"include"
:
[
"src"
],
"src"
],
"references"
:
[
"references"
:
[
{
{
"path"
:
"./tsconfig.node.json"
"path"
:
"./tsconfig.node.json"
}
}
]
]
}
}
\ No newline at end of file
Frontend/vite.config.ts
View file @
31f76dda
import
{
defineConfig
}
from
'vite'
import
{
defineConfig
}
from
'vite'
;
import
react
from
'@vitejs/plugin-react-swc'
import
react
from
'@vitejs/plugin-react-swc'
;
// https://vitejs.dev/config/
// https://vitejs.dev/config/
export
default
defineConfig
({
export
default
defineConfig
({
plugins
:
[
react
()],
plugins
:
[
react
()],
})
})
;
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment