├── FirstSpring
├── .gitignore
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── embarkx
│ │ │ └── FirstSpring
│ │ │ ├── FirstSpringApplication.java
│ │ │ ├── HelloController.java
│ │ │ └── HelloResponse.java
│ └── resources
│ │ └── application.properties
│ └── test
│ └── java
│ └── com
│ └── embarkx
│ └── FirstSpring
│ └── FirstSpringApplicationTests.java
├── Java Spring Boot- Professional eCommerce Project Masterclass.postman_collection.json
├── README.md
├── SpringExample
├── .gitignore
├── .idea
│ ├── .gitignore
│ ├── encodings.xml
│ ├── misc.xml
│ ├── uiDesigner.xml
│ └── vcs.xml
├── pom.xml
└── src
│ └── main
│ ├── java
│ ├── car
│ │ └── example
│ │ │ ├── bean
│ │ │ ├── App.java
│ │ │ └── MyBean.java
│ │ │ ├── constructor
│ │ │ └── setter
│ │ │ └── injection
│ │ │ ├── App.java
│ │ │ ├── Car.java
│ │ │ └── Specification.java
│ └── com
│ │ ├── example
│ │ ├── autowire
│ │ │ ├── constructor
│ │ │ ├── name
│ │ │ │ ├── App.java
│ │ │ │ ├── Car.java
│ │ │ │ └── Specification.java
│ │ │ └── type
│ │ │ │ ├── App.java
│ │ │ │ ├── Car.java
│ │ │ │ └── Specification.java
│ │ ├── autowired
│ │ │ └── annotation
│ │ │ │ ├── App.java
│ │ │ │ ├── AppConfig.java
│ │ │ │ ├── Employee.java
│ │ │ │ └── Manager.java
│ │ └── componentscan
│ │ │ ├── App.java
│ │ │ ├── Employee.java
│ │ │ └── annotation
│ │ │ ├── App.java
│ │ │ ├── AppConfig.java
│ │ │ └── Employee.java
│ │ ├── ioc
│ │ └── coupling
│ │ │ ├── IOCExample.java
│ │ │ ├── NewDatabaseProvider.java
│ │ │ ├── UserDataProvider.java
│ │ │ ├── UserDatabaseProvider.java
│ │ │ ├── UserManager.java
│ │ │ └── WebServiceDataProvider.java
│ │ ├── loose
│ │ └── coupling
│ │ │ ├── LooseCouplingExample.java
│ │ │ ├── NewDatabaseProvider.java
│ │ │ ├── UserDataProvider.java
│ │ │ ├── UserDatabaseProvider.java
│ │ │ ├── UserManager.java
│ │ │ └── WebServiceDataProvider.java
│ │ └── tight
│ │ └── coupling
│ │ ├── TightCouplingExample.java
│ │ ├── UserDatabase.java
│ │ └── UserManager.java
│ └── resources
│ ├── applicationBeanContext.xml
│ ├── applicationConstructorInjection.xml
│ ├── applicationIoCLooseCouplingExample.xml
│ ├── applicationSetterInjection.xml
│ ├── autowireByConstructor.xml
│ ├── autowireByName.xml
│ ├── autowireByType.xml
│ └── componentScanDemo.xml
├── ecom-frontend
├── .gitignore
├── README.md
├── eslint.config.js
├── index.html
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
│ └── vite.svg
├── src
│ ├── App.css
│ ├── App.jsx
│ ├── api
│ │ └── api.js
│ ├── assets
│ │ ├── react.svg
│ │ └── sliders
│ │ │ ├── s_1.webp
│ │ │ ├── s_2.webp
│ │ │ └── s_3.webp
│ ├── components
│ │ ├── About.jsx
│ │ ├── BackDrop.jsx
│ │ ├── Contact.jsx
│ │ ├── PrivateRoute.jsx
│ │ ├── UserMenu.jsx
│ │ ├── auth
│ │ │ ├── LogIn.jsx
│ │ │ └── Register.jsx
│ │ ├── cart
│ │ │ ├── Cart.jsx
│ │ │ ├── CartEmpty.jsx
│ │ │ ├── ItemContent.jsx
│ │ │ └── SetQuantity.jsx
│ │ ├── checkout
│ │ │ ├── AddAddressForm.jsx
│ │ │ ├── AddressInfo.jsx
│ │ │ ├── AddressInfoModal.jsx
│ │ │ ├── AddressList.jsx
│ │ │ ├── Checkout.jsx
│ │ │ ├── DeleteModal.jsx
│ │ │ ├── OrderSummary.jsx
│ │ │ ├── PaymentConfirmation.jsx
│ │ │ ├── PaymentForm.jsx
│ │ │ ├── PaymentMethod.jsx
│ │ │ ├── PaypalPayment.jsx
│ │ │ └── StripePayment.jsx
│ │ ├── home
│ │ │ ├── HeroBanner.jsx
│ │ │ └── Home.jsx
│ │ ├── products
│ │ │ ├── Filter.jsx
│ │ │ └── Products.jsx
│ │ └── shared
│ │ │ ├── ErrorPage.jsx
│ │ │ ├── InputField.jsx
│ │ │ ├── Loader.jsx
│ │ │ ├── Navbar.jsx
│ │ │ ├── Paginations.jsx
│ │ │ ├── ProductCard.jsx
│ │ │ ├── ProductViewModal.jsx
│ │ │ ├── Skeleton.jsx
│ │ │ ├── Spinners.jsx
│ │ │ └── Status.jsx
│ ├── hooks
│ │ └── useProductFilter.js
│ ├── index.css
│ ├── main.jsx
│ ├── store
│ │ ├── actions
│ │ │ └── index.js
│ │ └── reducers
│ │ │ ├── ProductReducer.js
│ │ │ ├── authReducer.js
│ │ │ ├── cartReducer.js
│ │ │ ├── errorReducer.js
│ │ │ ├── paymentMethodReducer.js
│ │ │ └── store.js
│ └── utils
│ │ ├── constant.js
│ │ ├── formatPrice.js
│ │ ├── index.js
│ │ └── truncateText.js
├── tailwind.config.js
└── vite.config.js
├── media
├── .gitignore
├── .mvn
│ └── wrapper
│ │ ├── maven-wrapper.jar
│ │ └── maven-wrapper.properties
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── social
│ │ │ └── media
│ │ │ ├── DataInitializer.java
│ │ │ ├── MediaApplication.java
│ │ │ ├── controllers
│ │ │ └── SocialController.java
│ │ │ ├── models
│ │ │ ├── Post.java
│ │ │ ├── SocialGroup.java
│ │ │ ├── SocialProfile.java
│ │ │ └── SocialUser.java
│ │ │ ├── repositories
│ │ │ ├── PostRepository.java
│ │ │ ├── SocialGroupRepository.java
│ │ │ ├── SocialProfileRepository.java
│ │ │ └── SocialUserRepository.java
│ │ │ └── services
│ │ │ └── SocialService.java
│ └── resources
│ │ └── application.properties
│ └── test
│ └── java
│ └── com
│ └── social
│ └── media
│ └── MediaApplicationTests.java
└── sb-ecom
├── .gitignore
├── .mvn
└── wrapper
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
├── images
├── 2aef0eb8-04eb-4f75-a717-773c0bb94a8f.jpg
└── 921e13ae-67f4-49d3-9340-4e6f29e1f312.jpg
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── ecommerce
│ │ └── project
│ │ ├── SbEcomApplication.java
│ │ ├── config
│ │ ├── AppConfig.java
│ │ ├── AppConstants.java
│ │ └── WebMvcConfig.java
│ │ ├── controller
│ │ ├── AddressController.java
│ │ ├── AuthController.java
│ │ ├── CartController.java
│ │ ├── CategoryController.java
│ │ ├── OrderController.java
│ │ └── ProductController.java
│ │ ├── exceptions
│ │ ├── APIException.java
│ │ ├── MyGlobalExceptionHandler.java
│ │ └── ResourceNotFoundException.java
│ │ ├── model
│ │ ├── Address.java
│ │ ├── AppRole.java
│ │ ├── Cart.java
│ │ ├── CartItem.java
│ │ ├── Category.java
│ │ ├── Order.java
│ │ ├── OrderItem.java
│ │ ├── Payment.java
│ │ ├── Product.java
│ │ ├── Role.java
│ │ └── User.java
│ │ ├── payload
│ │ ├── APIResponse.java
│ │ ├── AddressDTO.java
│ │ ├── CartDTO.java
│ │ ├── CartItemDTO.java
│ │ ├── CategoryDTO.java
│ │ ├── CategoryResponse.java
│ │ ├── OrderDTO.java
│ │ ├── OrderItemDTO.java
│ │ ├── OrderRequestDTO.java
│ │ ├── PaymentDTO.java
│ │ ├── ProductDTO.java
│ │ ├── ProductResponse.java
│ │ └── StripePaymentDto.java
│ │ ├── repositories
│ │ ├── AddressRepository.java
│ │ ├── CartItemRepository.java
│ │ ├── CartRepository.java
│ │ ├── CategoryRepository.java
│ │ ├── OrderItemRepository.java
│ │ ├── OrderRepository.java
│ │ ├── PaymentRepository.java
│ │ ├── ProductRepository.java
│ │ ├── RoleRepository.java
│ │ └── UserRepository.java
│ │ ├── security
│ │ ├── WebConfig.java
│ │ ├── WebSecurityConfig.java
│ │ ├── jwt
│ │ │ ├── AuthEntryPointJwt.java
│ │ │ ├── AuthTokenFilter.java
│ │ │ └── JwtUtils.java
│ │ ├── request
│ │ │ ├── LoginRequest.java
│ │ │ └── SignupRequest.java
│ │ ├── response
│ │ │ ├── MessageResponse.java
│ │ │ └── UserInfoResponse.java
│ │ └── services
│ │ │ ├── UserDetailsImpl.java
│ │ │ └── UserDetailsServiceImpl.java
│ │ ├── service
│ │ ├── AddressService.java
│ │ ├── AddressServiceImpl.java
│ │ ├── CartService.java
│ │ ├── CartServiceImpl.java
│ │ ├── CategoryService.java
│ │ ├── CategoryServiceImpl.java
│ │ ├── FileService.java
│ │ ├── FileServiceImpl.java
│ │ ├── OrderService.java
│ │ ├── OrderServiceImpl.java
│ │ ├── ProductService.java
│ │ ├── ProductServiceImpl.java
│ │ ├── StripeService.java
│ │ └── StripeServiceImpl.java
│ │ └── util
│ │ └── AuthUtil.java
└── resources
│ └── application.properties
└── test
└── java
└── com
└── ecommerce
└── project
└── SbEcomApplicationTests.java
/FirstSpring/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 |
--------------------------------------------------------------------------------
/FirstSpring/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.1.1
9 |
10 |
11 | com.embarkx
12 | FirstSpring
13 | 0.0.1-SNAPSHOT
14 | FirstSpring
15 | First project for Spring Boot
16 |
17 | 17
18 |
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-web
23 |
24 |
25 |
26 | org.springframework.boot
27 | spring-boot-starter-test
28 | test
29 |
30 |
31 |
32 |
33 |
34 |
35 | org.springframework.boot
36 | spring-boot-maven-plugin
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/FirstSpring/src/main/java/com/embarkx/FirstSpring/FirstSpringApplication.java:
--------------------------------------------------------------------------------
1 | package com.embarkx.FirstSpring;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class FirstSpringApplication {
8 |
9 |
10 | public static void main(String[] args) {
11 | SpringApplication.run(FirstSpringApplication.class, args);
12 | }
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/FirstSpring/src/main/java/com/embarkx/FirstSpring/HelloController.java:
--------------------------------------------------------------------------------
1 | package com.embarkx.FirstSpring;
2 |
3 | import org.springframework.web.bind.annotation.*;
4 |
5 | @RestController
6 | public class HelloController {
7 |
8 | @GetMapping("/hello/{name}")
9 | public HelloResponse helloParam(@PathVariable String name) {
10 | return new HelloResponse("Hello, " + name);
11 | }
12 |
13 | @GetMapping("/hello")
14 | public HelloResponse hello() {
15 | return new HelloResponse("Hello, World!");
16 | }
17 |
18 | @PostMapping("/hello")
19 | public HelloResponse helloPost(@RequestBody String name) {
20 | return new HelloResponse("Hello, " + name + "!");
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/FirstSpring/src/main/java/com/embarkx/FirstSpring/HelloResponse.java:
--------------------------------------------------------------------------------
1 | package com.embarkx.FirstSpring;
2 |
3 | public class HelloResponse {
4 | private String message;
5 |
6 | public HelloResponse(String message) {
7 | this.message = message;
8 | }
9 |
10 | public String getMessage() {
11 | return message;
12 | }
13 |
14 | public void setMessage(String message) {
15 | this.message = message;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/FirstSpring/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | server.port=8080
--------------------------------------------------------------------------------
/FirstSpring/src/test/java/com/embarkx/FirstSpring/FirstSpringApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.embarkx.FirstSpring;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | class FirstSpringApplicationTests {
8 |
9 | @Test
10 | void contextLoads() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/SpringExample/.gitignore:
--------------------------------------------------------------------------------
1 | target/
2 | !.mvn/wrapper/maven-wrapper.jar
3 | !**/src/main/**/target/
4 | !**/src/test/**/target/
5 |
6 | ### IntelliJ IDEA ###
7 | .idea/modules.xml
8 | .idea/jarRepositories.xml
9 | .idea/compiler.xml
10 | .idea/libraries/
11 | *.iws
12 | *.iml
13 | *.ipr
14 |
15 | ### Eclipse ###
16 | .apt_generated
17 | .classpath
18 | .factorypath
19 | .project
20 | .settings
21 | .springBeans
22 | .sts4-cache
23 |
24 | ### NetBeans ###
25 | /nbproject/private/
26 | /nbbuild/
27 | /dist/
28 | /nbdist/
29 | /.nb-gradle/
30 | build/
31 | !**/src/main/**/build/
32 | !**/src/test/**/build/
33 |
34 | ### VS Code ###
35 | .vscode/
36 |
37 | ### Mac OS ###
38 | .DS_Store
--------------------------------------------------------------------------------
/SpringExample/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/SpringExample/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/SpringExample/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/SpringExample/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/SpringExample/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | org.example
8 | SpringExample
9 | 1.0-SNAPSHOT
10 |
11 |
12 | 21
13 | 21
14 | UTF-8
15 |
16 |
17 |
18 |
19 |
20 |
21 | org.springframework
22 | spring-core
23 | 6.1.6
24 |
25 |
26 |
27 |
28 | org.springframework
29 | spring-context
30 | 6.1.6
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/car/example/bean/App.java:
--------------------------------------------------------------------------------
1 | package car.example.bean;
2 |
3 | import org.springframework.context.ApplicationContext;
4 | import org.springframework.context.support.ClassPathXmlApplicationContext;
5 |
6 | public class App {
7 | public static void main(String[] args) {
8 | ApplicationContext context
9 | = new ClassPathXmlApplicationContext("applicationBeanContext.xml");
10 |
11 | MyBean myBean = (MyBean) context.getBean("myBean");
12 | System.out.println(myBean);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/car/example/bean/MyBean.java:
--------------------------------------------------------------------------------
1 | package car.example.bean;
2 |
3 | public class MyBean {
4 | private String message;
5 |
6 | public void setMessage(String message) {
7 | this.message = message;
8 | }
9 |
10 | public void showMessage(){
11 | System.out.println("Message: " + message);
12 | }
13 |
14 | @Override
15 | public String toString() {
16 | return "MyBean{" +
17 | "message='" + message + '\'' +
18 | '}';
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/car/example/constructor/injection/App.java:
--------------------------------------------------------------------------------
1 | package car.example.constructor.injection;
2 |
3 | import org.springframework.context.ApplicationContext;
4 | import org.springframework.context.support.ClassPathXmlApplicationContext;
5 |
6 | public class App {
7 | public static void main(String[] args) {
8 | ApplicationContext context
9 | = new ClassPathXmlApplicationContext("applicationConstructorInjection.xml");
10 | Car myCar = (Car) context.getBean("myCar");
11 | myCar.displayDetails();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/car/example/constructor/injection/Car.java:
--------------------------------------------------------------------------------
1 | package car.example.constructor.injection;
2 |
3 | public class Car {
4 | private Specification specification;
5 |
6 | public Car(Specification specification) {
7 | this.specification = specification;
8 | }
9 |
10 | public void displayDetails(){
11 | System.out.println("Car Details: " + specification.toString());
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/car/example/constructor/injection/Specification.java:
--------------------------------------------------------------------------------
1 | package car.example.constructor.injection;
2 |
3 | public class Specification {
4 | private String make;
5 | private String model;
6 |
7 | public String getMake() {
8 | return make;
9 | }
10 |
11 | public void setMake(String make) {
12 | this.make = make;
13 | }
14 |
15 | public String getModel() {
16 | return model;
17 | }
18 |
19 | public void setModel(String model) {
20 | this.model = model;
21 | }
22 |
23 | @Override
24 | public String toString() {
25 | return "Specification{" +
26 | "make='" + make + '\'' +
27 | ", model='" + model + '\'' +
28 | '}';
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/car/example/setter/injection/App.java:
--------------------------------------------------------------------------------
1 | package car.example.setter.injection;
2 |
3 | import org.springframework.context.ApplicationContext;
4 | import org.springframework.context.support.ClassPathXmlApplicationContext;
5 |
6 | public class App {
7 | public static void main(String[] args) {
8 | ApplicationContext context
9 | = new ClassPathXmlApplicationContext("applicationSetterInjection.xml");
10 | Car myCar = (Car) context.getBean("myCar");
11 | myCar.displayDetails();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/car/example/setter/injection/Car.java:
--------------------------------------------------------------------------------
1 | package car.example.setter.injection;
2 |
3 | public class Car {
4 | private Specification specification;
5 |
6 | public void setSpecification(Specification specification) {
7 | this.specification = specification;
8 | }
9 |
10 | public void displayDetails(){
11 | System.out.println("Car Details: " + specification.toString());
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/car/example/setter/injection/Specification.java:
--------------------------------------------------------------------------------
1 | package car.example.setter.injection;
2 |
3 | public class Specification {
4 | private String make;
5 | private String model;
6 |
7 | public String getMake() {
8 | return make;
9 | }
10 |
11 | public void setMake(String make) {
12 | this.make = make;
13 | }
14 |
15 | public String getModel() {
16 | return model;
17 | }
18 |
19 | public void setModel(String model) {
20 | this.model = model;
21 | }
22 |
23 | @Override
24 | public String toString() {
25 | return "Specification{" +
26 | "make='" + make + '\'' +
27 | ", model='" + model + '\'' +
28 | '}';
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/example/autowire/constructor/App.java:
--------------------------------------------------------------------------------
1 | package com.example.autowire.constructor;
2 |
3 | import org.springframework.context.ApplicationContext;
4 | import org.springframework.context.support.ClassPathXmlApplicationContext;
5 |
6 | public class App {
7 | public static void main(String[] args) {
8 | ApplicationContext context
9 | = new ClassPathXmlApplicationContext("autowireByConstructor.xml");
10 | Car myCar = (Car) context.getBean("myCar");
11 | myCar.displayDetails();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/example/autowire/constructor/Car.java:
--------------------------------------------------------------------------------
1 | package com.example.autowire.constructor;
2 |
3 | public class Car {
4 | private Specification specification;
5 |
6 | public Car(Specification specification) {
7 | this.specification = specification;
8 | }
9 |
10 | // public void setSpecification(Specification specification) {
11 | // this.specification = specification;
12 | // }
13 |
14 | public void displayDetails(){
15 | System.out.println("Car Details: " + specification.toString());
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/example/autowire/constructor/Specification.java:
--------------------------------------------------------------------------------
1 | package com.example.autowire.constructor;
2 |
3 | public class Specification {
4 | private String make;
5 | private String model;
6 |
7 | public String getMake() {
8 | return make;
9 | }
10 |
11 | public void setMake(String make) {
12 | this.make = make;
13 | }
14 |
15 | public String getModel() {
16 | return model;
17 | }
18 |
19 | public void setModel(String model) {
20 | this.model = model;
21 | }
22 |
23 | @Override
24 | public String toString() {
25 | return "Specification{" +
26 | "make='" + make + '\'' +
27 | ", model='" + model + '\'' +
28 | '}';
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/example/autowire/name/App.java:
--------------------------------------------------------------------------------
1 | package com.example.autowire.name;
2 |
3 | import org.springframework.context.ApplicationContext;
4 | import org.springframework.context.support.ClassPathXmlApplicationContext;
5 |
6 | public class App {
7 | public static void main(String[] args) {
8 | ApplicationContext context
9 | = new ClassPathXmlApplicationContext("autowireByName.xml");
10 | Car myCar = (Car) context.getBean("myCar");
11 | myCar.displayDetails();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/example/autowire/name/Car.java:
--------------------------------------------------------------------------------
1 | package com.example.autowire.name;
2 |
3 | public class Car {
4 | private Specification specification;
5 |
6 | public void setSpecification(Specification specification) {
7 | this.specification = specification;
8 | }
9 |
10 | public void displayDetails(){
11 | System.out.println("Car Details: " + specification.toString());
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/example/autowire/name/Specification.java:
--------------------------------------------------------------------------------
1 | package com.example.autowire.name;
2 |
3 | public class Specification {
4 | private String make;
5 | private String model;
6 |
7 | public String getMake() {
8 | return make;
9 | }
10 |
11 | public void setMake(String make) {
12 | this.make = make;
13 | }
14 |
15 | public String getModel() {
16 | return model;
17 | }
18 |
19 | public void setModel(String model) {
20 | this.model = model;
21 | }
22 |
23 | @Override
24 | public String toString() {
25 | return "Specification{" +
26 | "make='" + make + '\'' +
27 | ", model='" + model + '\'' +
28 | '}';
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/example/autowire/type/App.java:
--------------------------------------------------------------------------------
1 | package com.example.autowire.type;
2 |
3 | import org.springframework.context.ApplicationContext;
4 | import org.springframework.context.support.ClassPathXmlApplicationContext;
5 |
6 | public class App {
7 | public static void main(String[] args) {
8 | ApplicationContext context
9 | = new ClassPathXmlApplicationContext("autowireByType.xml");
10 | Car myCar = (Car) context.getBean("myCar");
11 | myCar.displayDetails();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/example/autowire/type/Car.java:
--------------------------------------------------------------------------------
1 | package com.example.autowire.type;
2 |
3 | public class Car {
4 | private Specification specification;
5 |
6 | public void setSpecification(Specification specification) {
7 | this.specification = specification;
8 | }
9 |
10 | public void displayDetails(){
11 | System.out.println("Car Details: " + specification.toString());
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/example/autowire/type/Specification.java:
--------------------------------------------------------------------------------
1 | package com.example.autowire.type;
2 |
3 | public class Specification {
4 | private String make;
5 | private String model;
6 |
7 | public String getMake() {
8 | return make;
9 | }
10 |
11 | public void setMake(String make) {
12 | this.make = make;
13 | }
14 |
15 | public String getModel() {
16 | return model;
17 | }
18 |
19 | public void setModel(String model) {
20 | this.model = model;
21 | }
22 |
23 | @Override
24 | public String toString() {
25 | return "Specification{" +
26 | "make='" + make + '\'' +
27 | ", model='" + model + '\'' +
28 | '}';
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/example/autowired/annotation/App.java:
--------------------------------------------------------------------------------
1 | package com.example.autowired.annotation;
2 |
3 | import org.springframework.context.ApplicationContext;
4 | import org.springframework.context.annotation.AnnotationConfigApplicationContext;
5 |
6 | public class App {
7 | public static void main(String[] args) {
8 | ApplicationContext context
9 | = new AnnotationConfigApplicationContext(AppConfig.class);
10 | Employee employee = context.getBean("employee", Employee.class);
11 | System.out.println(employee.toString());
12 |
13 |
14 | Manager manager = context.getBean("manager", Manager.class);
15 | System.out.println(manager.toString());
16 | }
17 | }
18 |
19 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/example/autowired/annotation/AppConfig.java:
--------------------------------------------------------------------------------
1 | package com.example.autowired.annotation;
2 |
3 | import org.springframework.context.annotation.ComponentScan;
4 | import org.springframework.context.annotation.Configuration;
5 |
6 | @Configuration
7 | @ComponentScan(basePackages = "com.example.autowired.annotation")
8 | public class AppConfig {
9 | }
10 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/example/autowired/annotation/Employee.java:
--------------------------------------------------------------------------------
1 | package com.example.autowired.annotation;
2 |
3 | import org.springframework.beans.factory.annotation.Value;
4 | import org.springframework.stereotype.Component;
5 |
6 | @Component("employee")
7 | public class Employee {
8 | private int employeeId;
9 |
10 | @Value("Hello")
11 | private String firstName;
12 |
13 | @Value("${java.home}")
14 | private String lastName;
15 |
16 | @Value("#{4*4}")
17 | private double salary;
18 |
19 | public int getEmployeeId() {
20 | return employeeId;
21 | }
22 |
23 | public void setEmployeeId(int employeeId) {
24 | this.employeeId = employeeId;
25 | }
26 |
27 | public String getFirstName() {
28 | return firstName;
29 | }
30 |
31 | public void setFirstName(String firstName) {
32 | this.firstName = firstName;
33 | }
34 |
35 | public String getLastName() {
36 | return lastName;
37 | }
38 |
39 | public void setLastName(String lastName) {
40 | this.lastName = lastName;
41 | }
42 |
43 | public double getSalary() {
44 | return salary;
45 | }
46 |
47 | public void setSalary(double salary) {
48 | this.salary = salary;
49 | }
50 |
51 | @Override
52 | public String toString() {
53 | return "Employee{" +
54 | "employeeId=" + employeeId +
55 | ", firstName='" + firstName + '\'' +
56 | ", lastName='" + lastName + '\'' +
57 | ", salary=" + salary +
58 | '}';
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/example/autowired/annotation/Manager.java:
--------------------------------------------------------------------------------
1 | package com.example.autowired.annotation;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.beans.factory.annotation.Qualifier;
5 | import org.springframework.stereotype.Component;
6 |
7 | @Component
8 | public class Manager {
9 | @Autowired
10 | @Qualifier("employee")
11 | private Employee employee;
12 |
13 | /*@Autowired
14 | public Manager(Employee employee) {
15 | this.employee = employee;
16 | }*/
17 |
18 | @Override
19 | public String toString() {
20 | return "Manager{" +
21 | "employee=" + employee +
22 | '}';
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/example/componentscan/App.java:
--------------------------------------------------------------------------------
1 | package com.example.componentscan;
2 |
3 | import org.springframework.context.ApplicationContext;
4 | import org.springframework.context.support.ClassPathXmlApplicationContext;
5 |
6 | public class App {
7 | public static void main(String[] args) {
8 | ApplicationContext context
9 | = new ClassPathXmlApplicationContext("componentScanDemo.xml");
10 | Employee employee = context.getBean("employee", Employee.class);
11 | System.out.println(employee.toString());
12 | }
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/example/componentscan/Employee.java:
--------------------------------------------------------------------------------
1 | package com.example.componentscan;
2 |
3 | import org.springframework.beans.factory.annotation.Value;
4 | import org.springframework.stereotype.Component;
5 |
6 | @Component("employee")
7 | public class Employee {
8 | private int employeeId;
9 |
10 | @Value("Hello")
11 | private String firstName;
12 |
13 | @Value("${java.home}")
14 | private String lastName;
15 |
16 | @Value("#{4*4}")
17 | private double salary;
18 |
19 | public int getEmployeeId() {
20 | return employeeId;
21 | }
22 |
23 | public void setEmployeeId(int employeeId) {
24 | this.employeeId = employeeId;
25 | }
26 |
27 | public String getFirstName() {
28 | return firstName;
29 | }
30 |
31 | public void setFirstName(String firstName) {
32 | this.firstName = firstName;
33 | }
34 |
35 | public String getLastName() {
36 | return lastName;
37 | }
38 |
39 | public void setLastName(String lastName) {
40 | this.lastName = lastName;
41 | }
42 |
43 | public double getSalary() {
44 | return salary;
45 | }
46 |
47 | public void setSalary(double salary) {
48 | this.salary = salary;
49 | }
50 |
51 | @Override
52 | public String toString() {
53 | return "Employee{" +
54 | "employeeId=" + employeeId +
55 | ", firstName='" + firstName + '\'' +
56 | ", lastName='" + lastName + '\'' +
57 | ", salary=" + salary +
58 | '}';
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/example/componentscan/annotation/App.java:
--------------------------------------------------------------------------------
1 | package com.example.componentscan.annotation;
2 |
3 | import org.springframework.context.ApplicationContext;
4 | import org.springframework.context.annotation.AnnotationConfigApplicationContext;
5 | import org.springframework.context.support.ClassPathXmlApplicationContext;
6 |
7 | public class App {
8 | public static void main(String[] args) {
9 | ApplicationContext context
10 | = new AnnotationConfigApplicationContext(AppConfig.class);
11 | Employee employee = context.getBean("employee", Employee.class);
12 | System.out.println(employee.toString());
13 | }
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/example/componentscan/annotation/AppConfig.java:
--------------------------------------------------------------------------------
1 | package com.example.componentscan.annotation;
2 |
3 | import org.springframework.context.annotation.ComponentScan;
4 | import org.springframework.context.annotation.Configuration;
5 |
6 | @Configuration
7 | @ComponentScan(basePackages = "com.example.componentscan.annotation")
8 | public class AppConfig {
9 | }
10 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/example/componentscan/annotation/Employee.java:
--------------------------------------------------------------------------------
1 | package com.example.componentscan.annotation;
2 |
3 | import org.springframework.beans.factory.annotation.Value;
4 | import org.springframework.stereotype.Component;
5 |
6 | @Component("employee")
7 | public class Employee {
8 | private int employeeId;
9 |
10 | @Value("Hello")
11 | private String firstName;
12 |
13 | @Value("${java.home}")
14 | private String lastName;
15 |
16 | @Value("#{4*4}")
17 | private double salary;
18 |
19 | public int getEmployeeId() {
20 | return employeeId;
21 | }
22 |
23 | public void setEmployeeId(int employeeId) {
24 | this.employeeId = employeeId;
25 | }
26 |
27 | public String getFirstName() {
28 | return firstName;
29 | }
30 |
31 | public void setFirstName(String firstName) {
32 | this.firstName = firstName;
33 | }
34 |
35 | public String getLastName() {
36 | return lastName;
37 | }
38 |
39 | public void setLastName(String lastName) {
40 | this.lastName = lastName;
41 | }
42 |
43 | public double getSalary() {
44 | return salary;
45 | }
46 |
47 | public void setSalary(double salary) {
48 | this.salary = salary;
49 | }
50 |
51 | @Override
52 | public String toString() {
53 | return "Employee{" +
54 | "employeeId=" + employeeId +
55 | ", firstName='" + firstName + '\'' +
56 | ", lastName='" + lastName + '\'' +
57 | ", salary=" + salary +
58 | '}';
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/ioc/coupling/IOCExample.java:
--------------------------------------------------------------------------------
1 | package com.ioc.coupling;
2 |
3 | import org.springframework.context.ApplicationContext;
4 | import org.springframework.context.support.ClassPathXmlApplicationContext;
5 |
6 | public class IOCExample {
7 | public static void main(String[] args) {
8 | ApplicationContext context
9 | = new ClassPathXmlApplicationContext("applicationIoCLooseCouplingExample.xml");
10 |
11 | UserManager userManagerWithDB =
12 | (UserManager) context.getBean("userManagerWithUserDataProvider");
13 | System.out.println(userManagerWithDB.getUserInfo());
14 |
15 | UserManager userManagerWithWS =
16 | (UserManager) context.getBean("userManagerWithWebServiceProvider");
17 | System.out.println(userManagerWithWS.getUserInfo());
18 |
19 | UserManager userManagerWithNewDB =
20 | (UserManager) context.getBean("userManagerWithNewDatabaseProvider");
21 | System.out.println(userManagerWithNewDB.getUserInfo());
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/ioc/coupling/NewDatabaseProvider.java:
--------------------------------------------------------------------------------
1 | package com.ioc.coupling;
2 |
3 | public class NewDatabaseProvider implements UserDataProvider {
4 | @Override
5 | public String getUserDetails() {
6 | return "New Database in action";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/ioc/coupling/UserDataProvider.java:
--------------------------------------------------------------------------------
1 | package com.ioc.coupling;
2 |
3 | public interface UserDataProvider {
4 | String getUserDetails();
5 | }
6 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/ioc/coupling/UserDatabaseProvider.java:
--------------------------------------------------------------------------------
1 | package com.ioc.coupling;
2 |
3 | // A - MySQL, PostgreSQL
4 | // B - Web Service, MongoDB
5 |
6 | public class UserDatabaseProvider implements UserDataProvider {
7 | @Override
8 | public String getUserDetails(){
9 | // Directly access database here
10 | return "User Details From Database";
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/ioc/coupling/UserManager.java:
--------------------------------------------------------------------------------
1 | package com.ioc.coupling;
2 |
3 | public class UserManager {
4 | private UserDataProvider userDataProvider;
5 |
6 | public UserManager(UserDataProvider userDataProvider) {
7 | this.userDataProvider = userDataProvider;
8 | }
9 |
10 | public String getUserInfo(){
11 | return userDataProvider.getUserDetails();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/ioc/coupling/WebServiceDataProvider.java:
--------------------------------------------------------------------------------
1 | package com.ioc.coupling;
2 |
3 | public class WebServiceDataProvider implements UserDataProvider {
4 |
5 | @Override
6 | public String getUserDetails() {
7 | return "Fetching Data From WebService";
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/loose/coupling/LooseCouplingExample.java:
--------------------------------------------------------------------------------
1 | package com.loose.coupling;
2 |
3 | public class LooseCouplingExample {
4 | public static void main(String[] args) {
5 | UserDataProvider databaseProvider = new UserDatabaseProvider();
6 | UserManager userManagerWithDB = new UserManager(databaseProvider);
7 | System.out.println(userManagerWithDB.getUserInfo());
8 |
9 | UserDataProvider webServiceProvider = new WebServiceDataProvider();
10 | UserManager userManagerWithWS = new UserManager(webServiceProvider);
11 | System.out.println(userManagerWithWS.getUserInfo());
12 |
13 | UserDataProvider newDatabaseProvider = new NewDatabaseProvider();
14 | UserManager userManagerWithNewDB = new UserManager(newDatabaseProvider);
15 | System.out.println(userManagerWithNewDB.getUserInfo());
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/loose/coupling/NewDatabaseProvider.java:
--------------------------------------------------------------------------------
1 | package com.loose.coupling;
2 |
3 | public class NewDatabaseProvider implements UserDataProvider{
4 | @Override
5 | public String getUserDetails() {
6 | return "New Database in action";
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/loose/coupling/UserDataProvider.java:
--------------------------------------------------------------------------------
1 | package com.loose.coupling;
2 |
3 | public interface UserDataProvider {
4 | String getUserDetails();
5 | }
6 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/loose/coupling/UserDatabaseProvider.java:
--------------------------------------------------------------------------------
1 | package com.loose.coupling;
2 |
3 | // A - MySQL, PostgreSQL
4 | // B - Web Service, MongoDB
5 |
6 | public class UserDatabaseProvider implements UserDataProvider {
7 | @Override
8 | public String getUserDetails(){
9 | // Directly access database here
10 | return "User Details From Database";
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/loose/coupling/UserManager.java:
--------------------------------------------------------------------------------
1 | package com.loose.coupling;
2 |
3 | public class UserManager {
4 | private UserDataProvider userDataProvider;
5 |
6 | public UserManager(UserDataProvider userDataProvider) {
7 | this.userDataProvider = userDataProvider;
8 | }
9 |
10 | public String getUserInfo(){
11 | return userDataProvider.getUserDetails();
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/loose/coupling/WebServiceDataProvider.java:
--------------------------------------------------------------------------------
1 | package com.loose.coupling;
2 |
3 | public class WebServiceDataProvider implements UserDataProvider{
4 |
5 | @Override
6 | public String getUserDetails() {
7 | return "Fetching Data From WebService";
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/tight/coupling/TightCouplingExample.java:
--------------------------------------------------------------------------------
1 | package com.tight.coupling;
2 |
3 | public class TightCouplingExample {
4 | public static void main(String[] args) {
5 | UserManager userManager = new UserManager();
6 | System.out.println(userManager.getUserInfo());
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/tight/coupling/UserDatabase.java:
--------------------------------------------------------------------------------
1 | package com.tight.coupling;
2 |
3 | // A - MySQL, PostgreSQL
4 | // B - Web Service, MongoDB
5 |
6 | public class UserDatabase {
7 | public String getUserDetails(){
8 | // Directly access database here
9 | return "User Details From Database";
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/SpringExample/src/main/java/com/tight/coupling/UserManager.java:
--------------------------------------------------------------------------------
1 | package com.tight.coupling;
2 |
3 | public class UserManager {
4 | private UserDatabase userDatabase = new UserDatabase();
5 |
6 | public String getUserInfo(){
7 | return userDatabase.getUserDetails();
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/SpringExample/src/main/resources/applicationBeanContext.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/SpringExample/src/main/resources/applicationConstructorInjection.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/SpringExample/src/main/resources/applicationIoCLooseCouplingExample.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
10 |
11 |
13 |
14 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/SpringExample/src/main/resources/applicationSetterInjection.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/SpringExample/src/main/resources/autowireByConstructor.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/SpringExample/src/main/resources/autowireByName.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/SpringExample/src/main/resources/autowireByType.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/SpringExample/src/main/resources/componentScanDemo.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/ecom-frontend/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | dist
12 | dist-ssr
13 | *.local
14 |
15 | # Editor directories and files
16 | .vscode/*
17 | !.vscode/extensions.json
18 | .idea
19 | .DS_Store
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
26 | .env
--------------------------------------------------------------------------------
/ecom-frontend/README.md:
--------------------------------------------------------------------------------
1 | # React + Vite
2 |
3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
4 |
5 | Currently, two official plugins are available:
6 |
7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
9 |
--------------------------------------------------------------------------------
/ecom-frontend/eslint.config.js:
--------------------------------------------------------------------------------
1 | import js from '@eslint/js'
2 | import globals from 'globals'
3 | import react from 'eslint-plugin-react'
4 | import reactHooks from 'eslint-plugin-react-hooks'
5 | import reactRefresh from 'eslint-plugin-react-refresh'
6 |
7 | export default [
8 | { ignores: ['dist'] },
9 | {
10 | files: ['**/*.{js,jsx}'],
11 | languageOptions: {
12 | ecmaVersion: 2020,
13 | globals: globals.browser,
14 | parserOptions: {
15 | ecmaVersion: 'latest',
16 | ecmaFeatures: { jsx: true },
17 | sourceType: 'module',
18 | },
19 | },
20 | settings: { react: { version: '18.3' } },
21 | plugins: {
22 | react,
23 | 'react-hooks': reactHooks,
24 | 'react-refresh': reactRefresh,
25 | },
26 | rules: {
27 | ...js.configs.recommended.rules,
28 | ...react.configs.recommended.rules,
29 | ...react.configs['jsx-runtime'].rules,
30 | ...reactHooks.configs.recommended.rules,
31 | 'react/jsx-no-target-blank': 'off',
32 | 'react-refresh/only-export-components': [
33 | 'warn',
34 | { allowConstantExport: true },
35 | ],
36 | },
37 | },
38 | ]
39 |
--------------------------------------------------------------------------------
/ecom-frontend/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Vite + React
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/ecom-frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ecom-frontend",
3 | "private": true,
4 | "version": "0.0.0",
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "vite build",
9 | "lint": "eslint .",
10 | "preview": "vite preview"
11 | },
12 | "dependencies": {
13 | "@emotion/react": "^11.13.5",
14 | "@emotion/styled": "^11.13.5",
15 | "@headlessui/react": "^2.2.0",
16 | "@mui/material": "^6.1.8",
17 | "@reduxjs/toolkit": "^2.3.0",
18 | "@stripe/react-stripe-js": "^3.1.1",
19 | "@stripe/stripe-js": "^5.6.0",
20 | "axios": "^1.7.7",
21 | "react": "^18.3.1",
22 | "react-dom": "^18.3.1",
23 | "react-hook-form": "^7.54.0",
24 | "react-hot-toast": "^2.4.1",
25 | "react-icons": "^5.3.0",
26 | "react-loader-spinner": "^6.1.6",
27 | "react-redux": "^9.1.2",
28 | "react-router-dom": "^7.0.1",
29 | "swiper": "^11.1.15"
30 | },
31 | "devDependencies": {
32 | "@eslint/js": "^9.13.0",
33 | "@types/react": "^18.3.12",
34 | "@types/react-dom": "^18.3.1",
35 | "@vitejs/plugin-react": "^4.3.3",
36 | "autoprefixer": "^10.4.20",
37 | "eslint": "^9.13.0",
38 | "eslint-plugin-react": "^7.37.2",
39 | "eslint-plugin-react-hooks": "^5.0.0",
40 | "eslint-plugin-react-refresh": "^0.4.14",
41 | "globals": "^15.11.0",
42 | "postcss": "^8.4.49",
43 | "tailwindcss": "^3.4.15",
44 | "vite": "^5.4.10"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/ecom-frontend/postcss.config.js:
--------------------------------------------------------------------------------
1 | export default {
2 | plugins: {
3 | tailwindcss: {},
4 | autoprefixer: {},
5 | },
6 | }
7 |
--------------------------------------------------------------------------------
/ecom-frontend/public/vite.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ecom-frontend/src/App.css:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EmbarkXOfficial/spring-boot-course/7f0afdd1286487a90f199691005c6909e4371676/ecom-frontend/src/App.css
--------------------------------------------------------------------------------
/ecom-frontend/src/App.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react'
2 | import './App.css'
3 | import Products from './components/products/Products'
4 | import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
5 | import Home from './components/home/Home'
6 | import Navbar from './components/shared/Navbar'
7 | import About from './components/About'
8 | import Contact from './components/Contact'
9 | import { Toaster } from 'react-hot-toast'
10 | import Cart from './components/cart/Cart'
11 | import LogIn from './components/auth/LogIn'
12 | import PrivateRoute from './components/PrivateRoute'
13 | import Register from './components/auth/Register'
14 | import Checkout from './components/checkout/Checkout'
15 | import PaymentConfirmation from './components/checkout/PaymentConfirmation'
16 |
17 | function App() {
18 | return (
19 |
20 |
21 |
22 |
23 | }/>
24 | }/>
25 | }/>
26 | }/>
27 | }/>
28 |
29 | }>
30 | }/>
31 | }/>
32 |
33 |
34 | }>
35 | }/>
36 | }/>
37 |
38 |
39 |
40 |
41 |
42 | )
43 | }
44 |
45 | export default App
46 |
--------------------------------------------------------------------------------
/ecom-frontend/src/api/api.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | const api = axios.create({
4 | baseURL: `${import.meta.env.VITE_BACK_END_URL}/api`,
5 | withCredentials: true,
6 | });
7 |
8 | export default api;
--------------------------------------------------------------------------------
/ecom-frontend/src/assets/sliders/s_1.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EmbarkXOfficial/spring-boot-course/7f0afdd1286487a90f199691005c6909e4371676/ecom-frontend/src/assets/sliders/s_1.webp
--------------------------------------------------------------------------------
/ecom-frontend/src/assets/sliders/s_2.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EmbarkXOfficial/spring-boot-course/7f0afdd1286487a90f199691005c6909e4371676/ecom-frontend/src/assets/sliders/s_2.webp
--------------------------------------------------------------------------------
/ecom-frontend/src/assets/sliders/s_3.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EmbarkXOfficial/spring-boot-course/7f0afdd1286487a90f199691005c6909e4371676/ecom-frontend/src/assets/sliders/s_3.webp
--------------------------------------------------------------------------------
/ecom-frontend/src/components/About.jsx:
--------------------------------------------------------------------------------
1 | import ProductCard from "./shared/ProductCard";
2 |
3 | const products = [
4 | {
5 | image: "https://embarkx.com/sample/placeholder.png",
6 | productName: "iPhone 13 Pro Max",
7 | description:
8 | "The iPhone 13 Pro Max offers exceptional performance with its A15 Bionic chip, stunning Super Retina XDR display, and advanced camera features for breathtaking photos.",
9 | specialPrice: 720,
10 | price: 780,
11 | },
12 | {
13 | image: "https://embarkx.com/sample/placeholder.png",
14 | productName: "Samsung Galaxy S21",
15 | description:
16 | "Experience the brilliance of the Samsung Galaxy S21 with its vibrant AMOLED display, powerful camera, and sleek design that fits perfectly in your hand.",
17 | specialPrice: 699,
18 | price: 799,
19 | },
20 | {
21 | image: "https://embarkx.com/sample/placeholder.png",
22 | productName: "Google Pixel 6",
23 | description:
24 | "The Google Pixel 6 boasts cutting-edge AI features, exceptional photo quality, and a stunning display, making it a perfect choice for Android enthusiasts.",
25 | price: 599,
26 | specialPrice: 400,
27 | }
28 | ];
29 |
30 | const About = () => {
31 | return (
32 |
33 |
34 | About Us
35 |
36 |
37 |
38 |
39 | Welcome to our e-commerce store! We are dedicated to providing the
40 | best products and services to our customers. Our mission is to offer
41 | a seamless shopping experience while ensuring the highest quality of
42 | our offerings.
43 |
44 |
45 |
46 |
47 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | Our Products
58 |
59 |
60 | {products.map((product, index) => (
61 |
70 | ))
71 | }
72 |
73 |
74 |
75 |
76 |
77 | );
78 | }
79 |
80 | export default About;
--------------------------------------------------------------------------------
/ecom-frontend/src/components/BackDrop.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const BackDrop = ({ data }) => {
4 | return (
5 |
8 | )
9 | }
10 |
11 | export default BackDrop
--------------------------------------------------------------------------------
/ecom-frontend/src/components/Contact.jsx:
--------------------------------------------------------------------------------
1 | import { FaEnvelope, FaMapMarkedAlt, FaPhone } from "react-icons/fa";
2 |
3 | const Contact = () => {
4 | return(
5 |
8 |
9 |
10 |
Contact us
11 |
12 | We would love to hear from you! Please fill out the form below or contact us directly
13 |
14 |
15 |
51 |
52 |
53 |
Contact Information
54 |
55 |
56 |
57 | +4 8961 944 149
58 |
59 |
60 |
61 |
62 | embarkxofficial@gmail.com
63 |
64 |
65 |
66 |
67 | 123 Main, Town, USA
68 |
69 |
70 |
71 |
72 |
73 |
74 | );
75 | }
76 |
77 | export default Contact;
--------------------------------------------------------------------------------
/ecom-frontend/src/components/PrivateRoute.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { useSelector } from 'react-redux'
3 | import { Navigate, Outlet } from 'react-router-dom';
4 |
5 | const PrivateRoute = ({ publicPage = false }) => {
6 | const { user } = useSelector((state) => state.auth);
7 | if (publicPage) {
8 | return user ? :
9 | }
10 | return user ? : ;
11 | }
12 |
13 | export default PrivateRoute
--------------------------------------------------------------------------------
/ecom-frontend/src/components/UserMenu.jsx:
--------------------------------------------------------------------------------
1 | import { Avatar, Button, Menu, MenuItem } from '@mui/material';
2 | import React from 'react'
3 | import { BiUser } from 'react-icons/bi';
4 | import { FaShoppingCart } from 'react-icons/fa';
5 | import { IoExitOutline } from 'react-icons/io5';
6 | import { useDispatch, useSelector } from 'react-redux';
7 | import { Link, useNavigate } from 'react-router-dom';
8 | import BackDrop from './BackDrop';
9 | import { logOutUser } from '../store/actions';
10 |
11 | const UserMenu = () => {
12 | const [anchorEl, setAnchorEl] = React.useState(null);
13 | const open = Boolean(anchorEl);
14 | const { user } = useSelector((state) => state.auth);
15 | const dispatch = useDispatch();
16 | const navigate = useNavigate();
17 |
18 | const handleClick = (event) => {
19 | setAnchorEl(event.currentTarget);
20 | };
21 | const handleClose = () => {
22 | setAnchorEl(null);
23 | };
24 |
25 | const logOutHandler = () => {
26 | dispatch(logOutUser(navigate));
27 | };
28 |
29 | return (
30 |
31 |
37 |
80 |
81 | {open &&
}
82 |
83 | );
84 | }
85 |
86 | export default UserMenu
--------------------------------------------------------------------------------
/ecom-frontend/src/components/auth/LogIn.jsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import { useForm } from "react-hook-form";
3 | import { AiOutlineLogin } from "react-icons/ai";
4 | import { Link, useNavigate } from "react-router-dom";
5 | import InputField from "../shared/InputField";
6 | import { useDispatch } from "react-redux";
7 | import { authenticateSignInUser } from "../../store/actions";
8 | import toast from "react-hot-toast";
9 | import Spinners from "../shared/Spinners";
10 |
11 | const LogIn = () => {
12 | const navigate = useNavigate();
13 | const dispatch = useDispatch();
14 | const [loader, setLoader] = useState(false);
15 |
16 | const {
17 | register,
18 | handleSubmit,
19 | reset,
20 | formState: {errors},
21 | } = useForm({
22 | mode: "onTouched",
23 | });
24 |
25 | const loginHandler = async (data) => {
26 | console.log("Login Click");
27 | dispatch(authenticateSignInUser(data, toast, reset, navigate, setLoader));
28 | };
29 |
30 | return (
31 |
32 |
35 |
36 |
37 |
38 | Login Here
39 |
40 |
41 |
42 |
43 |
53 |
54 |
64 |
65 |
66 |
70 | {loader ? (
71 | <>
72 | Loading...
73 | >
74 | ) : (
75 | <>Login>
76 | )}
77 |
78 |
79 |
80 | Don't have an account?
81 |
84 | SignUp
85 |
86 |
87 |
88 | );
89 | }
90 |
91 | export default LogIn;
--------------------------------------------------------------------------------
/ecom-frontend/src/components/cart/Cart.jsx:
--------------------------------------------------------------------------------
1 | import { MdArrowBack, MdShoppingCart } from "react-icons/md";
2 | import { useDispatch, useSelector } from "react-redux";
3 | import { Link } from "react-router-dom";
4 | import ItemContent from "./ItemContent";
5 | import CartEmpty from "./CartEmpty";
6 | import { formatPrice } from "../../utils/formatPrice";
7 |
8 | const Cart = () => {
9 | const dispatch = useDispatch();
10 | const { cart } = useSelector((state) => state.carts);
11 | const newCart = { ...cart };
12 |
13 | newCart.totalPrice = cart?.reduce(
14 | (acc, cur) => acc + Number(cur?.specialPrice) * Number(cur?.quantity), 0
15 | );
16 |
17 | if (!cart || cart.length === 0) return ;
18 |
19 | return (
20 |
21 |
22 |
23 |
24 | Your Cart
25 |
26 |
All your selected items
27 |
28 |
29 |
30 |
31 | Product
32 |
33 |
34 |
35 | Price
36 |
37 |
38 |
39 | Quantity
40 |
41 |
42 |
43 | Total
44 |
45 |
46 |
47 |
48 | {cart && cart.length > 0 &&
49 | cart.map((item, i) => )}
50 |
51 |
52 |
53 |
54 |
55 |
56 | Subtotal
57 | {formatPrice(newCart?.totalPrice)}
58 |
59 |
60 |
61 | Taxes and shipping calculated at checkout
62 |
63 |
64 |
65 |
{}}
67 | className="font-semibold w-[300px] py-2 px-4 rounded-sm bg-customBlue text-white flex items-center justify-center gap-2 hover:text-gray-300 transition duration-500">
68 |
69 | Checkout
70 |
71 |
72 |
73 |
74 |
75 |
Continue Shopping
76 |
77 |
78 |
79 |
80 | );
81 | };
82 |
83 | export default Cart;
--------------------------------------------------------------------------------
/ecom-frontend/src/components/cart/CartEmpty.jsx:
--------------------------------------------------------------------------------
1 | import { MdArrowBack, MdShoppingCart } from "react-icons/md";
2 | import { Link } from "react-router-dom";
3 |
4 | const CartEmpty = () => {
5 | return (
6 |
7 |
8 |
9 |
10 | Your cart is empty
11 |
12 |
13 | Add some products to get started
14 |
15 |
16 |
17 |
20 |
21 | Start Shopping
22 |
23 |
24 |
25 | )
26 | }
27 |
28 | export default CartEmpty;
--------------------------------------------------------------------------------
/ecom-frontend/src/components/cart/SetQuantity.jsx:
--------------------------------------------------------------------------------
1 |
2 | const btnStyles = "border-[1.2px] border-slate-800 px-3 py-1 rounded";
3 | const SetQuantity = ({
4 | quantity,
5 | cardCounter,
6 | handeQtyIncrease,
7 | handleQtyDecrease,
8 | }) => {
9 | return (
10 |
11 | {cardCounter ? null :
QUANTITY
}
12 |
13 |
17 | -
18 |
19 |
{quantity}
20 |
23 | +
24 |
25 |
26 |
27 | );
28 | };
29 |
30 | export default SetQuantity;
--------------------------------------------------------------------------------
/ecom-frontend/src/components/checkout/AddressInfoModal.jsx:
--------------------------------------------------------------------------------
1 | import { Dialog, DialogBackdrop, DialogPanel, DialogTitle } from '@headlessui/react';
2 | import React from 'react'
3 | import { FaTimes } from 'react-icons/fa';
4 |
5 | const AddressInfoModal = ({ open, setOpen, children }) => {
6 | return (
7 | setOpen(false)} className="relative z-50">
8 | {/* The backdrop, rendered as a fixed sibling to the panel container */}
9 |
10 |
11 | {/* Full-screen container to center the panel */}
12 |
13 | {/* The actual dialog panel */}
14 |
15 |
16 | {children}
17 |
18 |
19 | setOpen(false)} type='button'>
20 |
21 |
22 |
23 |
24 |
25 |
26 | );
27 | }
28 |
29 | export default AddressInfoModal
--------------------------------------------------------------------------------
/ecom-frontend/src/components/checkout/AddressList.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { FaBuilding, FaCheckCircle, FaEdit, FaStreetView, FaTrash } from 'react-icons/fa';
3 | import { MdLocationCity, MdPinDrop, MdPublic } from "react-icons/md";
4 | import { useDispatch, useSelector } from 'react-redux'
5 | import { selectUserCheckoutAddress } from '../../store/actions';
6 |
7 | const AddressList = ({ addresses, setSelectedAddress, setOpenAddressModal, setOpenDeleteModal }) => {
8 | const dispatch = useDispatch();
9 | const { selectedUserCheckoutAddress } = useSelector((state) => state.auth);
10 |
11 | const onEditButtonHandler = (addresses) => {
12 | setSelectedAddress(addresses);
13 | setOpenAddressModal(true);
14 | };
15 |
16 | const onDeleteButtonHandler = (addresses) => {
17 | setSelectedAddress(addresses);
18 | setOpenDeleteModal(true);
19 | };
20 |
21 | const handleAddressSelection = (addresses) => {
22 | dispatch(selectUserCheckoutAddress(addresses));
23 | };
24 |
25 | return (
26 |
27 | {addresses.map((address) => (
28 |
handleAddressSelection(address)}
31 | className={`p-4 border rounded-md cursor-pointer relative ${
32 | selectedUserCheckoutAddress?.addressId === address.addressId
33 | ? "bg-green-100"
34 | : "bg-white"
35 | }`}>
36 |
37 |
38 |
39 |
40 |
{address.buildingName}
41 | {selectedUserCheckoutAddress?.addressId === address.addressId && (
42 |
43 | )}
44 |
45 |
46 |
47 |
48 |
{address.street}
49 |
50 |
51 |
52 |
53 |
{address.city}, {address.state}
54 |
55 |
56 |
57 |
58 |
{address.pincode}
59 |
60 |
61 |
62 |
63 |
{address.country}
64 |
65 |
66 |
67 |
68 |
69 |
70 | onEditButtonHandler(address)}>
71 |
72 |
73 | onDeleteButtonHandler(address)}>
74 |
75 |
76 |
77 |
78 | ))}
79 |
80 | )
81 | }
82 |
83 | export default AddressList
--------------------------------------------------------------------------------
/ecom-frontend/src/components/checkout/DeleteModal.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { FaExclamationTriangle } from "react-icons/fa";
3 | import { FaTimes } from "react-icons/fa";
4 | import {
5 | Dialog,
6 | DialogBackdrop,
7 | DialogPanel,
8 | DialogTitle,
9 | } from "@headlessui/react";
10 |
11 | export const DeleteModal = ({
12 | open,
13 | setOpen,
14 | title,
15 | onDeleteHandler,
16 | loader,
17 | }) => {
18 | return (
19 |
20 |
24 |
25 |
26 |
30 |
31 | setOpen(false)}
35 | className="rounded-md bg-white text-gray-400 hover:text-gray-500 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2"
36 | >
37 | Close
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
50 | {title}
51 |
52 |
53 |
54 | Are you sure you want to delete?
55 |
56 |
57 |
58 |
59 |
60 |
66 | {loader ? "Loading..." : "Delete"}
67 |
68 | setOpen(false)}
72 | className="mt-3 inline-flex w-full justify-center rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50 sm:mt-0 sm:w-auto"
73 | >
74 | Cancel
75 |
76 |
77 |
78 |
79 |
80 |
81 | );
82 | };
--------------------------------------------------------------------------------
/ecom-frontend/src/components/checkout/OrderSummary.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { formatPriceCalculation } from '../../utils/formatPrice'
3 |
4 | const OrderSummary = ({ totalPrice, cart, address, paymentMethod}) => {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 |
Billing Address
12 |
13 | Building Name:
14 | {address?.buildingName}
15 |
16 |
17 | City:
18 | {address?.city}
19 |
20 |
21 | Street:
22 | {address?.street}
23 |
24 |
25 | State:
26 | {address?.state}
27 |
28 |
29 | Pincode:
30 | {address?.pincode}
31 |
32 |
33 | Country:
34 | {address?.country}
35 |
36 |
37 |
38 |
39 | Payment Method
40 |
41 |
42 | Method:
43 | {paymentMethod}
44 |
45 |
46 |
47 |
48 |
Order Items
49 |
50 | {cart?.map((item) => (
51 |
52 |
57 |
58 |
{item?.productName}
59 |
60 | {item?.quantity} x ${item?.specialPrice} = ${
61 | formatPriceCalculation(item?.quantity, item?.specialPrice)
62 | }
63 |
64 |
65 |
66 | ))}
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
Order Summary
76 |
77 |
78 |
79 | Products
80 | ${formatPriceCalculation(totalPrice, 1)}
81 |
82 |
83 | Tax (0%)
84 | $0.00
85 |
86 |
87 | SubTotal
88 | ${formatPriceCalculation(totalPrice, 1)}
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | )
97 | }
98 |
99 | export default OrderSummary
--------------------------------------------------------------------------------
/ecom-frontend/src/components/checkout/PaymentConfirmation.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from 'react'
2 | import { FaCheckCircle } from 'react-icons/fa';
3 | import { useDispatch, useSelector } from 'react-redux';
4 | import { useLocation } from 'react-router-dom'
5 | import { stripePaymentConfirmation } from '../../store/actions';
6 | import toast from 'react-hot-toast';
7 |
8 | const PaymentConfirmation = () => {
9 | const location = useLocation();
10 | const searchParams = new URLSearchParams(location.search);
11 | const dispatch = useDispatch();
12 | const [errorMessage, setErrorMessage ] = useState("");
13 | const { cart } = useSelector((state) => state.carts);
14 | const [ loading, setLoading] = useState(false);
15 |
16 | const paymentIntent = searchParams.get("payment_intent");
17 | const clientSecret = searchParams.get("payment_intent_client_secret");
18 | const redirectStatus = searchParams.get("redirect_status");
19 | const selectedUserCheckoutAddress = localStorage.getItem("CHECKOUT_ADDRESS")
20 | ? JSON.parse(localStorage.getItem("CHECKOUT_ADDRESS"))
21 | : [];
22 |
23 | useEffect(() => {
24 | if (paymentIntent &&
25 | clientSecret &&
26 | redirectStatus &&
27 | cart &&
28 | cart?.length > 0
29 | ) {
30 | console.log(selectedUserCheckoutAddress);
31 | const sendData = {
32 | addressId: selectedUserCheckoutAddress.addressId,
33 | pgName: "Stripe",
34 | pgPaymentId: paymentIntent,
35 | pgStatus: "succeeded",
36 | pgResponseMessage: "Payment successful"
37 | };
38 | console.log(sendData);
39 | dispatch(stripePaymentConfirmation(sendData, setErrorMessage, setLoading, toast));
40 | }
41 | }, [paymentIntent, clientSecret, redirectStatus, cart]);
42 |
43 | return (
44 |
45 | {loading ? (
46 |
47 |
48 |
49 | ) : (
50 |
51 |
52 |
53 |
54 |
Payment Successful!
55 |
56 | Thank you for your purchase! Your payment was successful, and we’re
57 | processing your order.
58 |
59 |
60 | )}
61 |
62 | )
63 | }
64 |
65 | export default PaymentConfirmation
--------------------------------------------------------------------------------
/ecom-frontend/src/components/checkout/PaymentForm.jsx:
--------------------------------------------------------------------------------
1 | import { Skeleton } from '@mui/material';
2 | import { PaymentElement, useElements, useStripe } from '@stripe/react-stripe-js'
3 | import React from 'react'
4 | import { useState } from 'react';
5 |
6 | const PaymentForm = ({ clientSecret, totalPrice }) => {
7 | const stripe = useStripe();
8 | const elements = useElements();
9 | const [errorMessage, setErrorMessage] = useState("");
10 |
11 | const handleSubmit = async (e) => {
12 | e.preventDefault();
13 | if (!stripe || !elements) {
14 | return;
15 | }
16 |
17 | const { error: submitError } = await elements.submit();
18 |
19 | const { error } = await stripe.confirmPayment({
20 | elements,
21 | clientSecret,
22 | confirmParams: {
23 | return_url: `${import.meta.env.VITE_FRONTEND_URL}/order-confirm`,
24 | },
25 | });
26 |
27 | if (error) {
28 | setErrorMessage(error.message);
29 | return false;
30 | }
31 | };
32 |
33 | const paymentElementOptions = {
34 | layout: "tabs",
35 | }
36 |
37 | const isLoading = !clientSecret || !stripe || !elements;
38 |
39 | return (
40 |
41 | Payment Information
42 | {isLoading ? (
43 |
44 | ) : (
45 | <>
46 | {clientSecret && }
47 | {errorMessage && (
48 | {errorMessage}
49 | )}
50 |
51 |
54 | {!isLoading ? `Pay $${Number(totalPrice).toFixed(2)}`
55 | : "Processing"}
56 |
57 | >
58 | )}
59 |
60 | )
61 | }
62 |
63 | export default PaymentForm
--------------------------------------------------------------------------------
/ecom-frontend/src/components/checkout/PaymentMethod.jsx:
--------------------------------------------------------------------------------
1 | import { FormControl, FormControlLabel, Radio, RadioGroup } from '@mui/material'
2 | import React, { useEffect } from 'react'
3 | import { useDispatch, useSelector } from 'react-redux'
4 | import { addPaymentMethod, createUserCart } from '../../store/actions';
5 |
6 | const PaymentMethod = () => {
7 | const dispatch = useDispatch();
8 | const { paymentMethod } = useSelector((state) => state.payment);
9 | const { cart, cartId } = useSelector((state) => state.carts);
10 | const { isLoading, errorMessage } = useSelector((state) => state.errors);
11 |
12 | useEffect(() => {
13 | if (cart.length > 0 && !cartId && !errorMessage) {
14 | const sendCartItems = cart.map((item) => {
15 | return {
16 | productId: item.productId,
17 | quantity: item.quantity,
18 | };
19 | });
20 |
21 | dispatch(createUserCart(sendCartItems));
22 | }
23 | }, [dispatch, cartId]);
24 |
25 | const paymentMethodHandler = (method) => {
26 | dispatch(addPaymentMethod(method));
27 | }
28 | return (
29 |
30 |
Select Payment Method
31 |
32 | paymentMethodHandler(e.target.value)}
37 | >
38 | }
41 | label="Stripe"
42 | className='text-gray-700'/>
43 |
44 | }
47 | label="Paypal"
48 | className='text-gray-700'/>
49 |
50 |
51 |
52 | )
53 | }
54 |
55 | export default PaymentMethod
--------------------------------------------------------------------------------
/ecom-frontend/src/components/checkout/PaypalPayment.jsx:
--------------------------------------------------------------------------------
1 | import { Alert, AlertTitle } from '@mui/material'
2 | import React from 'react'
3 |
4 | const PaypalPayment = () => {
5 | return (
6 |
7 |
8 | Paypal Unavailable
9 | Paypal payment is unavailable. Please use another payment method.
10 |
11 |
12 | )
13 | }
14 |
15 | export default PaypalPayment
--------------------------------------------------------------------------------
/ecom-frontend/src/components/checkout/StripePayment.jsx:
--------------------------------------------------------------------------------
1 | import { Alert, AlertTitle, Skeleton } from '@mui/material'
2 | import { Elements } from '@stripe/react-stripe-js';
3 | import { loadStripe } from '@stripe/stripe-js';
4 | import React, { useEffect } from 'react'
5 | import { useDispatch, useSelector } from 'react-redux'
6 | import PaymentForm from './PaymentForm';
7 | import { createStripePaymentSecret } from '../../store/actions';
8 |
9 | const stripePromise = loadStripe(import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY);
10 |
11 | const StripePayment = () => {
12 | const dispatch = useDispatch();
13 | const { clientSecret } = useSelector((state) => state.auth);
14 | const { totalPrice } = useSelector((state) => state.carts);
15 | const { isLoading, errorMessage } = useSelector((state) => state.errors);
16 |
17 | useEffect(() => {
18 | if (!clientSecret) {
19 | dispatch(createStripePaymentSecret(totalPrice));
20 | }
21 | }, [clientSecret]);
22 |
23 | if (isLoading) {
24 | return (
25 |
26 |
27 |
28 | )
29 | }
30 |
31 |
32 | return (
33 | <>
34 | {clientSecret && (
35 |
36 |
37 |
38 | )}
39 | >
40 | )
41 | }
42 |
43 | export default StripePayment
--------------------------------------------------------------------------------
/ecom-frontend/src/components/home/HeroBanner.jsx:
--------------------------------------------------------------------------------
1 | // Import Swiper React components
2 | import { Swiper, SwiperSlide } from 'swiper/react';
3 | import 'swiper/css/navigation';
4 | import 'swiper/css/pagination';
5 | import 'swiper/css/scrollbar';
6 | import 'swiper/css/effect-fade';
7 | import 'swiper/css/autoplay';
8 |
9 | // Import Swiper styles
10 | import 'swiper/css';
11 | import { Autoplay, Pagination, EffectFade, Navigation } from 'swiper/modules';
12 |
13 | import { bannerLists } from '../../utils';
14 | import { Link } from 'react-router-dom';
15 |
16 | const colors = ["bg-banner-color1", "bg-banner-color2", "bg-banner-color3"];
17 |
18 | const HeroBanner = () => {
19 | return (
20 |
21 |
32 |
33 | {bannerLists.map((item, i) => (
34 |
35 |
36 |
37 |
38 |
39 |
40 | {item.title}
41 |
42 |
43 | {item.subtitle}
44 |
45 |
46 | {item.description}
47 |
48 |
51 | Shop
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | ))}
62 |
63 |
64 | );
65 | }
66 |
67 |
68 | export default HeroBanner;
--------------------------------------------------------------------------------
/ecom-frontend/src/components/home/Home.jsx:
--------------------------------------------------------------------------------
1 | import { useDispatch, useSelector } from "react-redux";
2 | import HeroBanner from "./HeroBanner";
3 | import { useEffect } from "react";
4 | import { fetchProducts } from "../../store/actions";
5 | import ProductCard from "../shared/ProductCard";
6 | import Loader from "../shared/Loader";
7 | import { FaExclamationTriangle } from "react-icons/fa";
8 |
9 | const Home = () => {
10 | const dispatch = useDispatch();
11 | const {products} = useSelector((state) => state.products);
12 | const { isLoading, errorMessage } = useSelector(
13 | (state) => state.errors
14 | );
15 | useEffect(() => {
16 | dispatch(fetchProducts());
17 | }, [dispatch]);
18 | return (
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
Products
27 |
28 | Discover our handpicked selection of top-rated items just for you!
29 |
30 |
31 |
32 |
33 | {isLoading ? (
34 |
35 | ) : errorMessage ? (
36 |
37 |
38 |
39 | {errorMessage}
40 |
41 |
42 | ) : (
43 |
44 | {products &&
45 | products?.slice(0,4)
46 | .map((item, i) =>
47 | )}
48 |
49 | )}
50 |
51 |
52 | )
53 | }
54 |
55 | export default Home;
--------------------------------------------------------------------------------
/ecom-frontend/src/components/products/Products.jsx:
--------------------------------------------------------------------------------
1 | import { FaExclamationTriangle } from "react-icons/fa";
2 | import ProductCard from "../shared/ProductCard";
3 | import { useDispatch, useSelector } from "react-redux";
4 | import { useEffect } from "react";
5 | import { fetchCategories } from "../../store/actions";
6 | import Filter from "./Filter";
7 | import useProductFilter from "../../hooks/useProductFilter";
8 | import Loader from "../shared/Loader";
9 | import Paginations from "../shared/Paginations";
10 |
11 | const Products = () => {
12 | const { isLoading, errorMessage } = useSelector(
13 | (state) => state.errors
14 | );
15 | const {products, categories, pagination} = useSelector(
16 | (state) => state.products
17 | )
18 | const dispatch = useDispatch();
19 | useProductFilter();
20 |
21 | useEffect(() => {
22 | dispatch(fetchCategories());
23 | }, [dispatch]);
24 |
25 | return (
26 |
27 |
28 | {isLoading ? (
29 |
30 | ) : errorMessage ? (
31 |
32 |
33 |
34 | {errorMessage}
35 |
36 |
37 | ) : (
38 |
39 |
40 | {products &&
41 | products.map((item, i) =>
42 | )}
43 |
44 |
49 |
50 | )}
51 |
52 | )
53 | }
54 |
55 | export default Products;
--------------------------------------------------------------------------------
/ecom-frontend/src/components/shared/ErrorPage.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import { FaExclamationTriangle } from 'react-icons/fa'
3 |
4 | const ErrorPage = ({ message}) => {
5 | return (
6 |
7 |
8 |
9 | {message ? message : "An unexpected error has occured"}
10 |
11 |
12 |
13 | )
14 | }
15 |
16 | export default ErrorPage
--------------------------------------------------------------------------------
/ecom-frontend/src/components/shared/InputField.jsx:
--------------------------------------------------------------------------------
1 | const InputField = ({
2 | label,
3 | id,
4 | type,
5 | errors,
6 | register,
7 | required,
8 | message,
9 | className,
10 | min,
11 | value,
12 | placeholder,
13 | }) => {
14 | return (
15 |
16 |
21 | {label}
22 |
23 |
52 |
53 | {errors[id]?.message && (
54 |
55 | {errors[id]?.message}
56 |
57 | )}
58 |
59 | );
60 | };
61 |
62 | export default InputField;
--------------------------------------------------------------------------------
/ecom-frontend/src/components/shared/Loader.jsx:
--------------------------------------------------------------------------------
1 | import { RotatingLines } from "react-loader-spinner";
2 |
3 | const Loader = ({ text }) => {
4 | return (
5 |
6 |
7 |
18 |
19 | {text ? text : "Please wait...." }
20 |
21 |
22 |
23 | );
24 | }
25 |
26 | export default Loader;
--------------------------------------------------------------------------------
/ecom-frontend/src/components/shared/Paginations.jsx:
--------------------------------------------------------------------------------
1 | import { Pagination } from "@mui/material";
2 | import { useLocation, useNavigate, useSearchParams } from "react-router-dom";
3 |
4 | const Paginations = ({ numberOfPage, totalProducts }) => {
5 | const [searchParams] = useSearchParams();
6 | const pathname = useLocation().pathname;
7 | const params = new URLSearchParams(searchParams);
8 | const navigate = useNavigate();
9 | const paramValue = searchParams.get("page")
10 | ? Number(searchParams.get("page"))
11 | : 1;
12 |
13 | const onChangeHandler = (event, value) => {
14 | params.set("page", value.toString());
15 | navigate(`${pathname}?${params}`);
16 | };
17 |
18 | return(
19 |
28 | )
29 | };
30 |
31 | export default Paginations;
--------------------------------------------------------------------------------
/ecom-frontend/src/components/shared/ProductViewModal.jsx:
--------------------------------------------------------------------------------
1 | import { Button, Dialog, DialogBackdrop, DialogPanel, DialogTitle } from '@headlessui/react'
2 | import { Divider } from '@mui/material';
3 | import { useState } from 'react'
4 | import Status from './Status';
5 | import { MdClose, MdDone } from 'react-icons/md';
6 |
7 | function ProductViewModal({open, setOpen, product, isAvailable}) {
8 |
9 | const {id, productName, image, description, quantity, price, discount, specialPrice} = product;
10 | const handleClickOpen = () => {
11 | setOpen(true);
12 | }
13 |
14 | return (
15 | <>
16 |
17 |
18 |
19 |
20 |
24 | {image && (
25 |
26 |
29 |
30 | )}
31 |
32 |
33 |
34 |
35 |
36 | {productName}
37 |
38 |
39 |
40 |
41 |
42 | {specialPrice ? (
43 |
44 |
45 | ${Number(price).toFixed(2)}
46 |
47 |
48 | ${Number(specialPrice).toFixed(2)}
49 |
50 |
51 | ) : (
52 |
53 | {" "}
54 | ${Number(price).toFixed(2)}
55 |
56 | )}
57 |
58 | {isAvailable ? (
59 |
65 | ) : (
66 |
72 | )}
73 |
74 |
75 |
76 |
77 |
{description}
78 |
79 |
80 |
81 |
82 |
83 | setOpen(false)}
85 | type="button"
86 | className="px-4 py-2 text-sm font-semibold text-slate-700 border border-slate-700 hover:text-slate-800 hover:border-slate-800 rounded-md "
87 | >
88 | Close
89 |
90 |
91 |
92 |
93 |
94 |
95 | >
96 | )
97 | }
98 |
99 | export default ProductViewModal;
--------------------------------------------------------------------------------
/ecom-frontend/src/components/shared/Spinners.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 |
3 | const Spinners = () => {
4 | return (
5 |
11 |
12 | )
13 | }
14 |
15 | export default Spinners;
--------------------------------------------------------------------------------
/ecom-frontend/src/components/shared/Status.jsx:
--------------------------------------------------------------------------------
1 | const Status = ({text, icon:Icon, bg, color}) => {
2 | return (
3 |
5 | {text}
6 |
7 | )
8 | };
9 |
10 | export default Status;
--------------------------------------------------------------------------------
/ecom-frontend/src/hooks/useProductFilter.js:
--------------------------------------------------------------------------------
1 | import { useEffect } from "react";
2 | import { useDispatch } from "react-redux";
3 | import { useSearchParams } from "react-router-dom";
4 | import { fetchProducts } from "../store/actions";
5 |
6 | const useProductFilter = () => {
7 | const [searchParams] = useSearchParams();
8 | const dispatch = useDispatch();
9 |
10 | useEffect(() => {
11 | const params = new URLSearchParams();
12 |
13 | const currentPage = searchParams.get("page")
14 | ? Number(searchParams.get("page"))
15 | : 1;
16 |
17 | params.set("pageNumber", currentPage - 1);
18 |
19 | const sortOrder = searchParams.get("sortby") || "asc";
20 | const categoryParams = searchParams.get("category") || null;
21 | const keyword = searchParams.get("keyword") || null;
22 | params.set("sortBy","price");
23 | params.set("sortOrder", sortOrder);
24 |
25 | if (categoryParams) {
26 | params.set("category", categoryParams);
27 | }
28 |
29 | if (keyword) {
30 | params.set("keyword", keyword);
31 | }
32 |
33 | const queryString = params.toString();
34 | console.log("QUERY STRING", queryString);
35 |
36 | dispatch(fetchProducts(queryString));
37 |
38 | }, [dispatch, searchParams]);
39 | };
40 |
41 | export default useProductFilter;
--------------------------------------------------------------------------------
/ecom-frontend/src/index.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100..900;1,100..900&display=swap');
2 |
3 | @tailwind base;
4 | @tailwind components;
5 | @tailwind utilities;
--------------------------------------------------------------------------------
/ecom-frontend/src/main.jsx:
--------------------------------------------------------------------------------
1 | import { StrictMode } from 'react'
2 | import { createRoot } from 'react-dom/client'
3 | import './index.css'
4 | import App from './App.jsx'
5 | import { Provider } from 'react-redux'
6 | import store from './store/reducers/store.js'
7 |
8 | createRoot(document.getElementById('root')).render(
9 |
10 |
11 | ,
12 | )
13 |
--------------------------------------------------------------------------------
/ecom-frontend/src/store/reducers/ProductReducer.js:
--------------------------------------------------------------------------------
1 | const initialState = {
2 | products: null,
3 | categories: null,
4 | pagination: {},
5 | };
6 |
7 | export const productReducer = (state = initialState, action) => {
8 | switch (action.type) {
9 | case "FETCH_PRODUCTS":
10 | return {
11 | ...state,
12 | products: action.payload,
13 | pagination: {
14 | ...state.pagination,
15 | pageNumber: action.pageNumber,
16 | pageSize: action.pageSize,
17 | totalElements: action.totalElements,
18 | totalPages: action.totalPages,
19 | lastPage: action.lastPage,
20 | },
21 | };
22 |
23 | case "FETCH_PRODUCTS":
24 | return {
25 | ...state,
26 | products: action.payload,
27 | pagination: {
28 | ...state.pagination,
29 | pageNumber: action.pageNumber,
30 | pageSize: action.pageSize,
31 | totalElements: action.totalElements,
32 | totalPages: action.totalPages,
33 | lastPage: action.lastPage,
34 | },
35 | };
36 |
37 | case "FETCH_CATEGORIES":
38 | return {
39 | ...state,
40 | categories: action.payload,
41 | pagination: {
42 | ...state.pagination,
43 | pageNumber: action.pageNumber,
44 | pageSize: action.pageSize,
45 | totalElements: action.totalElements,
46 | totalPages: action.totalPages,
47 | lastPage: action.lastPage,
48 | },
49 | };
50 |
51 |
52 | default:
53 | return state;
54 | }
55 | };
--------------------------------------------------------------------------------
/ecom-frontend/src/store/reducers/authReducer.js:
--------------------------------------------------------------------------------
1 | const initialState = {
2 | user: null,
3 | address: [],
4 | clientSecret: null,
5 | selectedUserCheckoutAddress: null,
6 | }
7 |
8 | export const authReducer = (state = initialState, action) => {
9 | switch (action.type) {
10 | case "LOGIN_USER":
11 | return { ...state, user: action.payload };
12 | case "USER_ADDRESS":
13 | return { ...state, address: action.payload };
14 | case "SELECT_CHECKOUT_ADDRESS":
15 | return { ...state, selectedUserCheckoutAddress: action.payload };
16 | case "REMOVE_CHECKOUT_ADDRESS":
17 | return { ...state, selectedUserCheckoutAddress: null };
18 | case "CLIENT_SECRET":
19 | return { ...state, clientSecret: action.payload };
20 | case "REMOVE_CLIENT_SECRET_ADDRESS":
21 | return { ...state, clientSecret: null, selectedUserCheckoutAddress: null };
22 | case "LOG_OUT":
23 | return {
24 | user: null,
25 | address: null,
26 | };
27 |
28 | default:
29 | return state;
30 | }
31 | };
--------------------------------------------------------------------------------
/ecom-frontend/src/store/reducers/cartReducer.js:
--------------------------------------------------------------------------------
1 | const initialState = {
2 | cart: [],
3 | totalPrice: 0,
4 | cartId: null,
5 | }
6 |
7 | export const cartReducer = (state = initialState, action) => {
8 | switch (action.type) {
9 | case "ADD_CART":
10 | const productToAdd = action.payload;
11 | const existingProduct = state.cart.find(
12 | (item) => item.productId === productToAdd.productId
13 | );
14 |
15 | if(existingProduct) {
16 | const updatedCart = state.cart.map((item) => {
17 | if (item.productId === productToAdd.productId) {
18 | return productToAdd;
19 | } else {
20 | return item;
21 | }
22 | });
23 |
24 | return {
25 | ...state,
26 | cart: updatedCart,
27 | };
28 | } else {
29 | const newCart = [...state.cart, productToAdd];
30 | return {
31 | ...state,
32 | cart: newCart,
33 | };
34 | }
35 | case "REMOVE_CART":
36 | return {
37 | ...state,
38 | cart: state.cart.filter(
39 | (item) => item.productId !== action.payload.productId
40 | ),
41 | };
42 | case "GET_USER_CART_PRODUCTS":
43 | return {
44 | ...state,
45 | cart: action.payload,
46 | totalPrice: action.totalPrice,
47 | cartId: action.cartId,
48 | };
49 | case "CLEAR_CART":
50 | return { cart:[], totalPrice: 0, cartId: null};
51 | default:
52 | return state;
53 | }
54 | return state;
55 | }
--------------------------------------------------------------------------------
/ecom-frontend/src/store/reducers/errorReducer.js:
--------------------------------------------------------------------------------
1 | const initialState = {
2 | isLoading: false,
3 | errorMessage: null,
4 | categoryLoader: false,
5 | categoryError: null,
6 | btnLoader: false,
7 | };
8 |
9 | export const errorReducer = (state = initialState, action) => {
10 | switch (action.type) {
11 | case "IS_FETCHING":
12 | return {
13 | ...state,
14 | isLoading: true,
15 | errorMessage: null,
16 | };
17 | case "BUTTON_LOADER":
18 | return {
19 | ...state,
20 | btnLoader: true,
21 | errorMessage: null,
22 | categoryError: null,
23 | };
24 | case "IS_SUCCESS":
25 | return {
26 | ...state,
27 | isLoading: false,
28 | errorMessage: null,
29 | btnLoader: false,
30 | categoryError: null,
31 | categoryLoader: false,
32 | };
33 | case "IS_ERROR":
34 | return {
35 | ...state,
36 | isLoading: false,
37 | errorMessage: action.payload,
38 | btnLoader: false,
39 | categoryLoader: false,
40 | }
41 | case "CATEGORY_SUCCESS":
42 | return {
43 | ...state,
44 | categoryLoader: false,
45 | categoryError: null,
46 | };
47 | case "CATEGORY_LOADER":
48 | return {
49 | ...state,
50 | categoryLoader: true,
51 | categoryError: null,
52 | errorMessage: null,
53 | }
54 |
55 | default:
56 | return state;
57 | }
58 | };
--------------------------------------------------------------------------------
/ecom-frontend/src/store/reducers/paymentMethodReducer.js:
--------------------------------------------------------------------------------
1 | const initialState = {
2 | paymentMethod: null,
3 | };
4 |
5 | export const paymentMethodReducer = (state = initialState, action) => {
6 | switch (action.type) {
7 | case "ADD_PAYMENT_METHOD":
8 | return {
9 | ...state,
10 | paymentMethod: action.payload,
11 | };
12 | default:
13 | return state;
14 | }
15 | };
--------------------------------------------------------------------------------
/ecom-frontend/src/store/reducers/store.js:
--------------------------------------------------------------------------------
1 | import { configureStore } from "@reduxjs/toolkit";
2 | import { productReducer } from "./ProductReducer";
3 | import { errorReducer } from "./errorReducer";
4 | import { cartReducer } from "./cartReducer";
5 | import { authReducer } from "./authReducer";
6 | import { paymentMethodReducer } from "./paymentMethodReducer";
7 |
8 | const user = localStorage.getItem("auth")
9 | ? JSON.parse(localStorage.getItem("auth"))
10 | : null;
11 |
12 | const cartItems = localStorage.getItem("cartItems")
13 | ? JSON.parse(localStorage.getItem("cartItems"))
14 | : [];
15 |
16 | const selectUserCheckoutAddress = localStorage.getItem("CHECKOUT_ADDRESS")
17 | ? JSON.parse(localStorage.getItem("CHECKOUT_ADDRESS"))
18 | : [];
19 |
20 | const initialState = {
21 | auth: { user: user, selectUserCheckoutAddress },
22 | carts: { cart: cartItems },
23 | };
24 |
25 | export const store = configureStore({
26 | reducer: {
27 | products: productReducer,
28 | errors: errorReducer,
29 | carts: cartReducer,
30 | auth: authReducer,
31 | payment: paymentMethodReducer,
32 | },
33 | preloadedState: initialState,
34 | });
35 |
36 | export default store;
--------------------------------------------------------------------------------
/ecom-frontend/src/utils/constant.js:
--------------------------------------------------------------------------------
1 | import bannerImageOne from "../assets/sliders/s_1.webp";
2 | import bannerImageTwo from "../assets/sliders/s_2.webp";
3 | import bannerImageThree from "../assets/sliders/s_3.webp";
4 |
5 | export {
6 | bannerImageOne,
7 | bannerImageTwo,
8 | bannerImageThree
9 | }
--------------------------------------------------------------------------------
/ecom-frontend/src/utils/formatPrice.js:
--------------------------------------------------------------------------------
1 | export const formatPrice = (amount) => {
2 | return new Intl.NumberFormat("en-US", {
3 | style: "currency",
4 | currency: "USD",
5 | }).format(amount);
6 | }
7 |
8 |
9 | export const formatPriceCalculation = (quantity, price) => {
10 | return (Number(quantity) * Number(price)).toFixed(2);
11 | }
--------------------------------------------------------------------------------
/ecom-frontend/src/utils/index.js:
--------------------------------------------------------------------------------
1 | import { bannerImageOne, bannerImageThree, bannerImageTwo } from "./constant";
2 |
3 | export const bannerLists = [
4 | {
5 | id: 1,
6 | image: bannerImageOne,
7 | title: "Home Comfort",
8 | subtitle: "Living Room",
9 | description: "Upgrade your space with cozy and stylish sofas",
10 | },
11 | {
12 | id: 2,
13 | image: bannerImageTwo,
14 | title: "Entertainment Hub",
15 | subtitle: "Smart TV",
16 | description: "Experience the latest in home entertainment",
17 | },
18 | {
19 | id: 3,
20 | image: bannerImageThree,
21 | title: "Playful Picks",
22 | subtitle: "Kids' Clothing",
23 | description: "Bright and fun styles for kids, up to 20% off",
24 | }
25 | ];
--------------------------------------------------------------------------------
/ecom-frontend/src/utils/truncateText.js:
--------------------------------------------------------------------------------
1 | const truncateText = (text, charLimit = 90) => {
2 | if (text?.length > charLimit) {
3 | return text.slice(0, charLimit) + "...";
4 | }
5 | return text;
6 | };
7 |
8 | export default truncateText;
--------------------------------------------------------------------------------
/ecom-frontend/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | export default {
3 | content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
4 | theme: {
5 | extend: {
6 | fontFamily: {
7 | montserrat: ["Montserrat", "sans-serif"],
8 | },
9 | boxShadow: {
10 | custom: "0 0 15px rgba(0, 0, 0, 0.3)",
11 | right: "10px 0px 10px -5px rgba(0, 0, 0, 0.3)",
12 | },
13 | colors: {
14 | customBlue: "rgba(28, 100, 242, 1)",
15 | banner: {
16 | color1: "#FDC200",
17 | color2: "#FF2C2C",
18 | color3: "#21AD61",
19 | color4: "#723DA6",
20 | },
21 | },
22 | backgroundImage: {
23 | "custom-gradient": "linear-gradient(to right, #111827, #1f2937)",
24 | "button-gradient": "linear-gradient(to right, #7e22ce, #ef4444)",
25 | "custom-gradient2": "linear-gradient(135deg, #f5f5f5, #eae7dc)",
26 | },
27 | },
28 | },
29 | plugins: [],
30 | };
31 |
--------------------------------------------------------------------------------
/ecom-frontend/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import react from '@vitejs/plugin-react'
3 |
4 | // https://vite.dev/config/
5 | export default defineConfig({
6 | plugins: [react()],
7 | })
8 |
--------------------------------------------------------------------------------
/media/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | ### IntelliJ IDEA ###
17 | .idea
18 | *.iws
19 | *.iml
20 | *.ipr
21 |
22 | ### NetBeans ###
23 | /nbproject/private/
24 | /nbbuild/
25 | /dist/
26 | /nbdist/
27 | /.nb-gradle/
28 | build/
29 | !**/src/main/**/build/
30 | !**/src/test/**/build/
31 |
32 | ### VS Code ###
33 | .vscode/
34 |
--------------------------------------------------------------------------------
/media/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EmbarkXOfficial/spring-boot-course/7f0afdd1286487a90f199691005c6909e4371676/media/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/media/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.6/apache-maven-3.9.6-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
3 |
--------------------------------------------------------------------------------
/media/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.2.5
9 |
10 |
11 | com.social
12 | media
13 | 0.0.1-SNAPSHOT
14 | media
15 | Demo project for Spring Boot
16 |
17 | 17
18 |
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-data-jpa
23 |
24 |
25 | org.springframework.boot
26 | spring-boot-starter-web
27 |
28 |
29 |
30 | com.h2database
31 | h2
32 | runtime
33 |
34 |
35 | org.springframework.boot
36 | spring-boot-starter-test
37 | test
38 |
39 |
40 | org.projectlombok
41 | lombok
42 | true
43 |
44 |
45 |
46 |
47 |
48 |
49 | org.springframework.boot
50 | spring-boot-maven-plugin
51 |
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/media/src/main/java/com/social/media/MediaApplication.java:
--------------------------------------------------------------------------------
1 | package com.social.media;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class MediaApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(MediaApplication.class, args);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/media/src/main/java/com/social/media/controllers/SocialController.java:
--------------------------------------------------------------------------------
1 | package com.social.media.controllers;
2 |
3 | import com.social.media.models.SocialUser;
4 | import com.social.media.services.SocialService;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.http.HttpStatus;
7 | import org.springframework.http.ResponseEntity;
8 | import org.springframework.web.bind.annotation.*;
9 |
10 | import java.util.List;
11 |
12 | @RestController
13 | public class SocialController {
14 | @Autowired
15 | private SocialService socialService;
16 |
17 | @GetMapping("/social/users")
18 | public ResponseEntity> getUsers(){
19 | return new ResponseEntity<>(socialService.getAllUsers(), HttpStatus.OK);
20 | }
21 |
22 | @PostMapping("/social/users")
23 | public ResponseEntity saveUser(@RequestBody SocialUser socialUser){
24 | return new ResponseEntity<>(socialService.saveUser(socialUser), HttpStatus.CREATED);
25 | }
26 |
27 | @DeleteMapping("/social/users/{userId}")
28 | public ResponseEntity deleteUser(@PathVariable Long userId){
29 | socialService.deleteUser(userId);
30 | return new ResponseEntity<>("Deleted Successfully", HttpStatus.OK);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/media/src/main/java/com/social/media/models/Post.java:
--------------------------------------------------------------------------------
1 | package com.social.media.models;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnore;
4 | import jakarta.persistence.*;
5 | import lombok.AllArgsConstructor;
6 | import lombok.Data;
7 | import lombok.NoArgsConstructor;
8 |
9 | @Entity
10 | @Data
11 | @NoArgsConstructor
12 | @AllArgsConstructor
13 | public class Post {
14 | @Id
15 | @GeneratedValue(strategy = GenerationType.IDENTITY)
16 | private Long id;
17 |
18 | @ManyToOne
19 | @JoinColumn(name = "user_id")
20 | @JsonIgnore
21 | private SocialUser socialUser;
22 | }
23 |
--------------------------------------------------------------------------------
/media/src/main/java/com/social/media/models/SocialGroup.java:
--------------------------------------------------------------------------------
1 | package com.social.media.models;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnore;
4 | import jakarta.persistence.*;
5 | import lombok.AllArgsConstructor;
6 | import lombok.Data;
7 | import lombok.NoArgsConstructor;
8 |
9 | import java.util.HashSet;
10 | import java.util.Objects;
11 | import java.util.Set;
12 |
13 | @Entity
14 | @Data
15 | @NoArgsConstructor
16 | @AllArgsConstructor
17 | public class SocialGroup {
18 | @Id
19 | @GeneratedValue(strategy = GenerationType.IDENTITY)
20 | private Long id;
21 |
22 | @ManyToMany(mappedBy = "groups")
23 | @JsonIgnore
24 | private Set socialUsers = new HashSet<>();
25 |
26 | @Override
27 | public int hashCode(){
28 | return Objects.hash(id);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/media/src/main/java/com/social/media/models/SocialProfile.java:
--------------------------------------------------------------------------------
1 | package com.social.media.models;
2 |
3 | import com.fasterxml.jackson.annotation.JsonIgnore;
4 | import jakarta.persistence.*;
5 | import lombok.AllArgsConstructor;
6 | import lombok.Data;
7 | import lombok.NoArgsConstructor;
8 |
9 | @Entity
10 | @Data
11 | @NoArgsConstructor
12 | @AllArgsConstructor
13 | public class SocialProfile {
14 | @Id
15 | @GeneratedValue(strategy = GenerationType.IDENTITY)
16 | private Long id;
17 |
18 | @OneToOne
19 | @JoinColumn(name = "social_user")
20 | @JsonIgnore
21 | private SocialUser user;
22 |
23 | private String description;
24 |
25 | public void setSocialUser(SocialUser socialUser){
26 | this.user = socialUser;
27 | if (user.getSocialProfile() != this)
28 | user.setSocialProfile(this);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/media/src/main/java/com/social/media/models/SocialUser.java:
--------------------------------------------------------------------------------
1 | package com.social.media.models;
2 |
3 | import jakarta.persistence.*;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import java.util.*;
9 |
10 |
11 | @Entity
12 | @Data
13 | @NoArgsConstructor
14 | @AllArgsConstructor
15 | public class SocialUser {
16 | @Id
17 | @GeneratedValue(strategy = GenerationType.IDENTITY)
18 | private Long id;
19 |
20 | @OneToOne(mappedBy = "user",
21 | cascade = {CascadeType.REMOVE, CascadeType.PERSIST, CascadeType.MERGE})
22 | //@JoinColumn(name = "social_profile_id")
23 | private SocialProfile socialProfile;
24 |
25 | @OneToMany(mappedBy = "socialUser", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
26 | private List posts = new ArrayList<>();
27 |
28 | @ManyToMany(fetch = FetchType.LAZY)
29 | @JoinTable(
30 | name = "user_group",
31 | joinColumns = @JoinColumn(name = "user_id"),
32 | inverseJoinColumns = @JoinColumn(name = "group_id")
33 | )
34 | private Set groups = new HashSet<>();
35 |
36 | @Override
37 | public int hashCode(){
38 | return Objects.hash(id);
39 | }
40 |
41 | public void setSocialProfile(SocialProfile socialProfile){
42 | socialProfile.setUser(this);
43 | this.socialProfile = socialProfile;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/media/src/main/java/com/social/media/repositories/PostRepository.java:
--------------------------------------------------------------------------------
1 | package com.social.media.repositories;
2 |
3 | import com.social.media.models.Post;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | public interface PostRepository extends JpaRepository {
7 | }
8 |
--------------------------------------------------------------------------------
/media/src/main/java/com/social/media/repositories/SocialGroupRepository.java:
--------------------------------------------------------------------------------
1 | package com.social.media.repositories;
2 |
3 | import com.social.media.models.SocialGroup;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | public interface SocialGroupRepository extends JpaRepository {
7 | }
8 |
--------------------------------------------------------------------------------
/media/src/main/java/com/social/media/repositories/SocialProfileRepository.java:
--------------------------------------------------------------------------------
1 | package com.social.media.repositories;
2 |
3 | import com.social.media.models.SocialProfile;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | public interface SocialProfileRepository extends JpaRepository {
7 | }
8 |
--------------------------------------------------------------------------------
/media/src/main/java/com/social/media/repositories/SocialUserRepository.java:
--------------------------------------------------------------------------------
1 | package com.social.media.repositories;
2 |
3 | import com.social.media.models.SocialUser;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | public interface SocialUserRepository extends JpaRepository {
7 | }
8 |
--------------------------------------------------------------------------------
/media/src/main/java/com/social/media/services/SocialService.java:
--------------------------------------------------------------------------------
1 | package com.social.media.services;
2 |
3 | import com.social.media.models.SocialUser;
4 | import com.social.media.repositories.SocialUserRepository;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.stereotype.Service;
7 |
8 | import java.util.List;
9 |
10 | @Service
11 | public class SocialService {
12 | @Autowired
13 | SocialUserRepository socialUserRepository;
14 |
15 | public List getAllUsers() {
16 | return socialUserRepository.findAll();
17 | }
18 |
19 | public SocialUser saveUser(SocialUser socialUser) {
20 | return socialUserRepository.save(socialUser);
21 | }
22 |
23 | public SocialUser deleteUser(Long id) {
24 | SocialUser socialUser = socialUserRepository.findById(id)
25 | .orElseThrow(() -> new RuntimeException("User not found"));
26 | socialUserRepository.delete(socialUser);
27 | return socialUser;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/media/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | spring.application.name=media
2 | spring.h2.console.enabled=true
3 | spring.datasource.url=jdbc:h2:mem:test
4 |
5 | spring.jpa.show-sql=true
6 | spring.jpa.properties.hibernate.format_sql=true
--------------------------------------------------------------------------------
/media/src/test/java/com/social/media/MediaApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.social.media;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | class MediaApplicationTests {
8 |
9 | @Test
10 | void contextLoads() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/sb-ecom/.gitignore:
--------------------------------------------------------------------------------
1 | HELP.md
2 | target/
3 | !.mvn/wrapper/maven-wrapper.jar
4 | !**/src/main/**/target/
5 | !**/src/test/**/target/
6 |
7 | ### STS ###
8 | .apt_generated
9 | .classpath
10 | .factorypath
11 | .project
12 | .settings
13 | .springBeans
14 | .sts4-cache
15 |
16 | # Ignore the images folder
17 | images/
18 |
19 |
20 | ### IntelliJ IDEA ###
21 | .idea
22 | *.iws
23 | *.iml
24 | *.ipr
25 |
26 | ### NetBeans ###
27 | /nbproject/private/
28 | /nbbuild/
29 | /dist/
30 | /nbdist/
31 | /.nb-gradle/
32 | build/
33 | !**/src/main/**/build/
34 | !**/src/test/**/build/
35 |
36 | ### VS Code ###
37 | .vscode/
38 |
--------------------------------------------------------------------------------
/sb-ecom/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EmbarkXOfficial/spring-boot-course/7f0afdd1286487a90f199691005c6909e4371676/sb-ecom/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/sb-ecom/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip
2 | wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
3 |
--------------------------------------------------------------------------------
/sb-ecom/images/2aef0eb8-04eb-4f75-a717-773c0bb94a8f.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EmbarkXOfficial/spring-boot-course/7f0afdd1286487a90f199691005c6909e4371676/sb-ecom/images/2aef0eb8-04eb-4f75-a717-773c0bb94a8f.jpg
--------------------------------------------------------------------------------
/sb-ecom/images/921e13ae-67f4-49d3-9340-4e6f29e1f312.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/EmbarkXOfficial/spring-boot-course/7f0afdd1286487a90f199691005c6909e4371676/sb-ecom/images/921e13ae-67f4-49d3-9340-4e6f29e1f312.jpg
--------------------------------------------------------------------------------
/sb-ecom/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | org.springframework.boot
7 | spring-boot-starter-parent
8 | 3.2.5
9 |
10 |
11 | com.ecommerce
12 | sb-ecom
13 | 0.0.1-SNAPSHOT
14 | sb-ecom
15 | Spring Boot Ecommerce Project
16 |
17 | 17
18 |
19 |
20 |
21 | org.springframework.boot
22 | spring-boot-starter-web
23 |
24 |
25 | org.springframework.boot
26 | spring-boot-starter-data-jpa
27 |
28 |
29 | com.stripe
30 | stripe-java
31 | 28.0.0
32 |
33 |
34 | org.postgresql
35 | postgresql
36 | runtime
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | org.projectlombok
47 | lombok
48 | true
49 |
50 |
51 |
52 | org.springframework.boot
53 | spring-boot-starter-validation
54 |
55 |
56 |
57 | org.springframework.boot
58 | spring-boot-starter-test
59 | test
60 |
61 |
62 |
63 | org.modelmapper
64 | modelmapper
65 | 3.0.0
66 |
67 |
68 |
69 | org.springframework.boot
70 | spring-boot-starter-security
71 |
72 |
73 |
74 |
75 | io.jsonwebtoken
76 | jjwt-api
77 | 0.12.5
78 |
79 |
80 | io.jsonwebtoken
81 | jjwt-impl
82 | 0.12.5
83 | runtime
84 |
85 |
86 | io.jsonwebtoken
87 | jjwt-jackson
88 | 0.12.5
89 | runtime
90 |
91 |
92 |
93 | org.springframework.security
94 | spring-security-test
95 | test
96 |
97 |
98 |
99 |
100 |
101 |
102 | org.springframework.boot
103 | spring-boot-maven-plugin
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/SbEcomApplication.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project;
2 |
3 | import org.springframework.boot.SpringApplication;
4 | import org.springframework.boot.autoconfigure.SpringBootApplication;
5 |
6 | @SpringBootApplication
7 | public class SbEcomApplication {
8 |
9 | public static void main(String[] args) {
10 | SpringApplication.run(SbEcomApplication.class, args);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/config/AppConfig.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.config;
2 |
3 | import org.modelmapper.ModelMapper;
4 | import org.springframework.context.annotation.Bean;
5 | import org.springframework.context.annotation.Configuration;
6 |
7 | @Configuration
8 | public class AppConfig {
9 |
10 | @Bean
11 | public ModelMapper modelMapper(){
12 | return new ModelMapper();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/config/AppConstants.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.config;
2 |
3 | public class AppConstants {
4 | public static final String PAGE_NUMBER = "0";
5 | public static final String PAGE_SIZE = "50";
6 | public static final String SORT_CATEGORIES_BY = "categoryId";
7 | public static final String SORT_PRODUCTS_BY = "productId";
8 | public static final String SORT_DIR = "asc";
9 | }
10 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/config/WebMvcConfig.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.config;
2 |
3 | import org.springframework.context.annotation.Configuration;
4 | import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
5 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
6 |
7 | @Configuration
8 | public class WebMvcConfig implements WebMvcConfigurer {
9 | @Override
10 | public void addResourceHandlers(ResourceHandlerRegistry registry) {
11 | registry.addResourceHandler("/images/**").addResourceLocations("file:images/");
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/controller/AddressController.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.controller;
2 |
3 | import com.ecommerce.project.model.User;
4 | import com.ecommerce.project.payload.AddressDTO;
5 | import com.ecommerce.project.service.AddressService;
6 | import com.ecommerce.project.util.AuthUtil;
7 | import jakarta.validation.Valid;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.http.HttpStatus;
10 | import org.springframework.http.ResponseEntity;
11 | import org.springframework.web.bind.annotation.*;
12 |
13 | import java.util.List;
14 |
15 | @RestController
16 | @RequestMapping("/api")
17 | public class AddressController {
18 |
19 | @Autowired
20 | AuthUtil authUtil;
21 |
22 | @Autowired
23 | AddressService addressService;
24 |
25 | @PostMapping("/addresses")
26 | public ResponseEntity createAddress(@Valid @RequestBody AddressDTO addressDTO){
27 | User user = authUtil.loggedInUser();
28 | AddressDTO savedAddressDTO = addressService.createAddress(addressDTO, user);
29 | return new ResponseEntity<>(savedAddressDTO, HttpStatus.CREATED);
30 | }
31 |
32 | @GetMapping("/addresses")
33 | public ResponseEntity> getAddresses(){
34 | List addressList = addressService.getAddresses();
35 | return new ResponseEntity<>(addressList, HttpStatus.OK);
36 | }
37 |
38 | @GetMapping("/addresses/{addressId}")
39 | public ResponseEntity getAddressById(@PathVariable Long addressId){
40 | AddressDTO addressDTO = addressService.getAddressesById(addressId);
41 | return new ResponseEntity<>(addressDTO, HttpStatus.OK);
42 | }
43 |
44 |
45 | @GetMapping("/users/addresses")
46 | public ResponseEntity> getUserAddresses(){
47 | User user = authUtil.loggedInUser();
48 | List addressList = addressService.getUserAddresses(user);
49 | return new ResponseEntity<>(addressList, HttpStatus.OK);
50 | }
51 |
52 | @PutMapping("/addresses/{addressId}")
53 | public ResponseEntity updateAddress(@PathVariable Long addressId
54 | , @RequestBody AddressDTO addressDTO){
55 | AddressDTO updatedAddress = addressService.updateAddress(addressId, addressDTO);
56 | return new ResponseEntity<>(updatedAddress, HttpStatus.OK);
57 | }
58 |
59 | @DeleteMapping("/addresses/{addressId}")
60 | public ResponseEntity updateAddress(@PathVariable Long addressId){
61 | String status = addressService.deleteAddress(addressId);
62 | return new ResponseEntity<>(status, HttpStatus.OK);
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/controller/CartController.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.controller;
2 |
3 | import com.ecommerce.project.model.Cart;
4 | import com.ecommerce.project.payload.CartDTO;
5 | import com.ecommerce.project.payload.CartItemDTO;
6 | import com.ecommerce.project.repositories.CartRepository;
7 | import com.ecommerce.project.service.CartService;
8 | import com.ecommerce.project.util.AuthUtil;
9 | import org.springframework.beans.factory.annotation.Autowired;
10 | import org.springframework.http.HttpStatus;
11 | import org.springframework.http.ResponseEntity;
12 | import org.springframework.web.bind.annotation.*;
13 |
14 | import java.util.List;
15 |
16 | @RestController
17 | @RequestMapping("/api")
18 | public class CartController {
19 |
20 | @Autowired
21 | private CartRepository cartRepository;
22 |
23 | @Autowired
24 | private AuthUtil authUtil;
25 |
26 | @Autowired
27 | private CartService cartService;
28 |
29 | @PostMapping("/cart/create")
30 | public ResponseEntity createOrUpdateCart(@RequestBody List cartItems){
31 | String response = cartService.createOrUpdateCartWithItems(cartItems);
32 | return new ResponseEntity<>(response, HttpStatus.CREATED);
33 | }
34 |
35 | @PostMapping("/carts/products/{productId}/quantity/{quantity}")
36 | public ResponseEntity addProductToCart(@PathVariable Long productId,
37 | @PathVariable Integer quantity){
38 | CartDTO cartDTO = cartService.addProductToCart(productId, quantity);
39 | return new ResponseEntity(cartDTO, HttpStatus.CREATED);
40 | }
41 |
42 | @GetMapping("/carts")
43 | public ResponseEntity> getCarts() {
44 | List cartDTOs = cartService.getAllCarts();
45 | return new ResponseEntity>(cartDTOs, HttpStatus.FOUND);
46 | }
47 |
48 | @GetMapping("/carts/users/cart")
49 | public ResponseEntity getCartById(){
50 | String emailId = authUtil.loggedInEmail();
51 | Cart cart = cartRepository.findCartByEmail(emailId);
52 | Long cartId = cart.getCartId();
53 | CartDTO cartDTO = cartService.getCart(emailId, cartId);
54 | return new ResponseEntity(cartDTO, HttpStatus.OK);
55 | }
56 |
57 | @PutMapping("/cart/products/{productId}/quantity/{operation}")
58 | public ResponseEntity updateCartProduct(@PathVariable Long productId,
59 | @PathVariable String operation) {
60 |
61 | CartDTO cartDTO = cartService.updateProductQuantityInCart(productId,
62 | operation.equalsIgnoreCase("delete") ? -1 : 1);
63 |
64 | return new ResponseEntity(cartDTO, HttpStatus.OK);
65 | }
66 |
67 | @DeleteMapping("/carts/{cartId}/product/{productId}")
68 | public ResponseEntity deleteProductFromCart(@PathVariable Long cartId,
69 | @PathVariable Long productId) {
70 | String status = cartService.deleteProductFromCart(cartId, productId);
71 |
72 | return new ResponseEntity(status, HttpStatus.OK);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/controller/CategoryController.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.controller;
2 |
3 | import com.ecommerce.project.config.AppConstants;
4 | import com.ecommerce.project.payload.CategoryDTO;
5 | import com.ecommerce.project.payload.CategoryResponse;
6 | import com.ecommerce.project.service.CategoryService;
7 | import jakarta.validation.Valid;
8 | import org.springframework.beans.factory.annotation.Autowired;
9 | import org.springframework.http.HttpStatus;
10 | import org.springframework.http.ResponseEntity;
11 | import org.springframework.web.bind.annotation.*;
12 |
13 | @RestController
14 | @RequestMapping("/api")
15 | public class CategoryController {
16 |
17 | @Autowired
18 | private CategoryService categoryService;
19 |
20 | @GetMapping("/public/categories")
21 | public ResponseEntity getAllCategories(
22 | @RequestParam(name = "pageNumber", defaultValue = AppConstants.PAGE_NUMBER, required = false) Integer pageNumber,
23 | @RequestParam(name = "pageSize", defaultValue = AppConstants.PAGE_SIZE, required = false) Integer pageSize,
24 | @RequestParam(name = "sortBy", defaultValue = AppConstants.SORT_CATEGORIES_BY, required = false) String sortBy,
25 | @RequestParam(name = "sortOrder", defaultValue = AppConstants.SORT_DIR, required = false) String sortOrder) {
26 | CategoryResponse categoryResponse = categoryService.getAllCategories(pageNumber, pageSize, sortBy, sortOrder);
27 | return new ResponseEntity<>(categoryResponse, HttpStatus.OK);
28 | }
29 |
30 | @PostMapping("/public/categories")
31 | public ResponseEntity createCategory(@Valid @RequestBody CategoryDTO categoryDTO){
32 | CategoryDTO savedCategoryDTO = categoryService.createCategory(categoryDTO);
33 | return new ResponseEntity<>(savedCategoryDTO, HttpStatus.CREATED);
34 | }
35 |
36 | @DeleteMapping("/admin/categories/{categoryId}")
37 | public ResponseEntity deleteCategory(@PathVariable Long categoryId){
38 | CategoryDTO deletedCategory = categoryService.deleteCategory(categoryId);
39 | return new ResponseEntity<>(deletedCategory, HttpStatus.OK);
40 | }
41 |
42 |
43 | @PutMapping("/public/categories/{categoryId}")
44 | public ResponseEntity updateCategory(@Valid @RequestBody CategoryDTO categoryDTO,
45 | @PathVariable Long categoryId){
46 | CategoryDTO savedCategoryDTO = categoryService.updateCategory(categoryDTO, categoryId);
47 | return new ResponseEntity<>(savedCategoryDTO, HttpStatus.OK);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/controller/OrderController.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.controller;
2 |
3 | import com.ecommerce.project.payload.OrderDTO;
4 | import com.ecommerce.project.payload.OrderRequestDTO;
5 | import com.ecommerce.project.payload.StripePaymentDto;
6 | import com.ecommerce.project.service.OrderService;
7 | import com.ecommerce.project.service.StripeService;
8 | import com.ecommerce.project.util.AuthUtil;
9 | import com.stripe.exception.StripeException;
10 | import com.stripe.model.PaymentIntent;
11 | import org.springframework.beans.factory.annotation.Autowired;
12 | import org.springframework.http.HttpStatus;
13 | import org.springframework.http.ResponseEntity;
14 | import org.springframework.web.bind.annotation.*;
15 |
16 | @RestController
17 | @RequestMapping("/api")
18 | public class OrderController {
19 |
20 | @Autowired
21 | private OrderService orderService;
22 |
23 | @Autowired
24 | private AuthUtil authUtil;
25 |
26 | @Autowired
27 | private StripeService stripeService;
28 |
29 | @PostMapping("/order/users/payments/{paymentMethod}")
30 | public ResponseEntity orderProducts(@PathVariable String paymentMethod, @RequestBody OrderRequestDTO orderRequestDTO) {
31 | String emailId = authUtil.loggedInEmail();
32 | System.out.println("orderRequestDTO DATA: " + orderRequestDTO);
33 | OrderDTO order = orderService.placeOrder(
34 | emailId,
35 | orderRequestDTO.getAddressId(),
36 | paymentMethod,
37 | orderRequestDTO.getPgName(),
38 | orderRequestDTO.getPgPaymentId(),
39 | orderRequestDTO.getPgStatus(),
40 | orderRequestDTO.getPgResponseMessage()
41 | );
42 | return new ResponseEntity<>(order, HttpStatus.CREATED);
43 | }
44 |
45 | @PostMapping("/order/stripe-client-secret")
46 | public ResponseEntity createStripeClientSecret(@RequestBody StripePaymentDto stripePaymentDto) throws StripeException {
47 | PaymentIntent paymentIntent = stripeService.paymentIntent(stripePaymentDto);
48 | return new ResponseEntity<>(paymentIntent.getClientSecret(), HttpStatus.CREATED);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/exceptions/APIException.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.exceptions;
2 |
3 | public class APIException extends RuntimeException {
4 | private static final long serialVersionUID = 1L;
5 |
6 | public APIException() {
7 | }
8 |
9 | public APIException(String message) {
10 | super(message);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/exceptions/MyGlobalExceptionHandler.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.exceptions;
2 |
3 |
4 | import com.ecommerce.project.payload.APIResponse;
5 | import org.springframework.http.HttpStatus;
6 | import org.springframework.http.ResponseEntity;
7 | import org.springframework.validation.FieldError;
8 | import org.springframework.web.bind.MethodArgumentNotValidException;
9 | import org.springframework.web.bind.annotation.ExceptionHandler;
10 | import org.springframework.web.bind.annotation.RestControllerAdvice;
11 |
12 | import java.util.HashMap;
13 | import java.util.Map;
14 |
15 | @RestControllerAdvice
16 | public class MyGlobalExceptionHandler {
17 |
18 | @ExceptionHandler(MethodArgumentNotValidException.class)
19 | public ResponseEntity> myMethodArgumentNotValidException(MethodArgumentNotValidException e) {
20 | Map response = new HashMap<>();
21 | e.getBindingResult().getAllErrors().forEach(err -> {
22 | String fieldName = ((FieldError) err).getField();
23 | String message = err.getDefaultMessage();
24 | response.put(fieldName, message);
25 | });
26 | return new ResponseEntity>(response,
27 | HttpStatus.BAD_REQUEST);
28 | }
29 |
30 | @ExceptionHandler(ResourceNotFoundException.class)
31 | public ResponseEntity myResourceNotFoundException(ResourceNotFoundException e) {
32 | String message = e.getMessage();
33 | APIResponse apiResponse = new APIResponse(message, false);
34 | return new ResponseEntity<>(apiResponse, HttpStatus.NOT_FOUND);
35 | }
36 |
37 | @ExceptionHandler(APIException.class)
38 | public ResponseEntity myAPIException(APIException e) {
39 | String message = e.getMessage();
40 | APIResponse apiResponse = new APIResponse(message, false);
41 | return new ResponseEntity<>(apiResponse, HttpStatus.BAD_REQUEST);
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/exceptions/ResourceNotFoundException.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.exceptions;
2 |
3 | public class ResourceNotFoundException extends RuntimeException {
4 | String resourceName;
5 | String field;
6 | String fieldName;
7 | Long fieldId;
8 |
9 | public ResourceNotFoundException() {
10 | }
11 |
12 | public ResourceNotFoundException(String resourceName, String field, String fieldName) {
13 | super(String.format("%s not found with %s: %s", resourceName, field, fieldName));
14 | this.resourceName = resourceName;
15 | this.field = field;
16 | this.fieldName = fieldName;
17 | }
18 |
19 | public ResourceNotFoundException(String resourceName, String field, Long fieldId) {
20 | super(String.format("%s not found with %s: %d", resourceName, field, fieldId));
21 | this.resourceName = resourceName;
22 | this.field = field;
23 | this.fieldId = fieldId;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/model/Address.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.model;
2 |
3 | import jakarta.persistence.*;
4 | import jakarta.validation.constraints.NotBlank;
5 | import jakarta.validation.constraints.Size;
6 | import lombok.AllArgsConstructor;
7 | import lombok.Data;
8 | import lombok.NoArgsConstructor;
9 | import lombok.ToString;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 | @Entity
15 | @Table(name = "addresses")
16 | @Data
17 | @NoArgsConstructor
18 | @AllArgsConstructor
19 | public class Address {
20 | @Id
21 | @GeneratedValue(strategy = GenerationType.IDENTITY)
22 | private Long addressId;
23 |
24 | @NotBlank
25 | @Size(min = 5, message = "Street name must be atleast 5 characters")
26 | private String street;
27 |
28 | @NotBlank
29 | @Size(min = 5, message = "Building name must be atleast 5 characters")
30 | private String buildingName;
31 |
32 | @NotBlank
33 | @Size(min = 4, message = "City name must be atleast 4 characters")
34 | private String city;
35 |
36 | @NotBlank
37 | @Size(min = 2, message = "State name must be atleast 2 characters")
38 | private String state;
39 |
40 | @NotBlank
41 | @Size(min = 2, message = "Country name must be atleast 2 characters")
42 | private String country;
43 |
44 | @NotBlank
45 | @Size(min = 5, message = "Pincode must be atleast 5 characters")
46 | private String pincode;
47 |
48 | @ManyToOne
49 | @JoinColumn(name = "user_id")
50 | private User user;
51 |
52 | public Address(String street, String buildingName, String city, String state, String country, String pincode) {
53 | this.street = street;
54 | this.buildingName = buildingName;
55 | this.city = city;
56 | this.state = state;
57 | this.country = country;
58 | this.pincode = pincode;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/model/AppRole.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.model;
2 |
3 | public enum AppRole {
4 | ROLE_USER,
5 | ROLE_SELLER,
6 | ROLE_ADMIN
7 | }
8 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/model/Cart.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.model;
2 |
3 | import jakarta.persistence.*;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | import java.util.ArrayList;
9 | import java.util.List;
10 |
11 | @Entity
12 | @Data
13 | @Table(name = "carts")
14 | @NoArgsConstructor
15 | @AllArgsConstructor
16 | public class Cart {
17 | @Id
18 | @GeneratedValue(strategy = GenerationType.IDENTITY)
19 | private Long cartId;
20 |
21 | @OneToOne
22 | @JoinColumn(name = "user_id")
23 | private User user;
24 |
25 | @OneToMany(mappedBy = "cart", cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, orphanRemoval = true)
26 | private List cartItems = new ArrayList<>();
27 |
28 | private Double totalPrice = 0.0;
29 | }
30 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/model/CartItem.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.model;
2 |
3 | import jakarta.persistence.*;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | @Entity
9 | @Data
10 | @Table(name = "cart_items")
11 | @NoArgsConstructor
12 | @AllArgsConstructor
13 | public class CartItem {
14 | @Id
15 | @GeneratedValue(strategy = GenerationType.IDENTITY)
16 | private Long cartItemId;
17 |
18 | @ManyToOne
19 | @JoinColumn(name = "cart_id")
20 | private Cart cart;
21 |
22 | @ManyToOne
23 | @JoinColumn(name = "product_id")
24 | private Product product;
25 |
26 | private Integer quantity;
27 | private double discount;
28 | private double productPrice;
29 | }
30 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/model/Category.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.model;
2 |
3 | import jakarta.persistence.*;
4 | import jakarta.validation.constraints.NotBlank;
5 | import jakarta.validation.constraints.Size;
6 | import lombok.AllArgsConstructor;
7 | import lombok.Data;
8 | import lombok.NoArgsConstructor;
9 |
10 | import java.util.List;
11 |
12 | @Entity(name = "categories")
13 | @Data
14 | @NoArgsConstructor
15 | @AllArgsConstructor
16 | public class Category {
17 | @Id
18 | @GeneratedValue(strategy = GenerationType.IDENTITY)
19 | private Long categoryId;
20 |
21 | @NotBlank
22 | @Size(min = 5, message = "Category name must contain atleast 5 characters")
23 | private String categoryName;
24 |
25 | @OneToMany(mappedBy = "category", cascade = CascadeType.ALL)
26 | private List products;
27 | }
28 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/model/Order.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.model;
2 |
3 | import jakarta.persistence.*;
4 | import jakarta.validation.constraints.Email;
5 | import lombok.AllArgsConstructor;
6 | import lombok.Data;
7 | import lombok.NoArgsConstructor;
8 |
9 | import java.time.LocalDate;
10 | import java.util.ArrayList;
11 | import java.util.List;
12 |
13 | @Entity
14 | @Table(name = "orders")
15 | @Data
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | public class Order {
19 |
20 | @Id
21 | @GeneratedValue(strategy = GenerationType.IDENTITY)
22 | private Long orderId;
23 |
24 | @Email
25 | @Column(nullable = false)
26 | private String email;
27 |
28 | @OneToMany(mappedBy = "order", cascade = { CascadeType.PERSIST, CascadeType.MERGE })
29 | private List orderItems = new ArrayList<>();
30 |
31 | private LocalDate orderDate;
32 |
33 | @OneToOne
34 | @JoinColumn(name = "payment_id")
35 | private Payment payment;
36 |
37 | private Double totalAmount;
38 | private String orderStatus;
39 |
40 | // Reference to Address
41 | @ManyToOne
42 | @JoinColumn(name = "address_id")
43 | private Address address;
44 | }
45 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/model/OrderItem.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.model;
2 |
3 | import jakarta.persistence.*;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 |
8 | @Entity
9 | @Data
10 | @Table(name = "order_items")
11 | @AllArgsConstructor
12 | @NoArgsConstructor
13 | public class OrderItem {
14 |
15 | @Id
16 | @GeneratedValue(strategy = GenerationType.IDENTITY)
17 | private Long orderItemId;
18 |
19 | @ManyToOne
20 | @JoinColumn(name = "product_id")
21 | private Product product;
22 |
23 | @ManyToOne
24 | @JoinColumn(name = "order_id")
25 | private Order order;
26 |
27 | private Integer quantity;
28 | private double discount;
29 | private double orderedProductPrice;
30 |
31 | }
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/model/Payment.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.model;
2 |
3 | import jakarta.persistence.*;
4 | import jakarta.validation.constraints.NotBlank;
5 | import jakarta.validation.constraints.Size;
6 | import lombok.AllArgsConstructor;
7 | import lombok.Data;
8 | import lombok.NoArgsConstructor;
9 |
10 | @Entity
11 | @Table(name = "payments")
12 | @Data
13 | @NoArgsConstructor
14 | @AllArgsConstructor
15 | public class Payment {
16 |
17 | @Id
18 | @GeneratedValue(strategy = GenerationType.IDENTITY)
19 | private Long paymentId;
20 |
21 | @OneToOne(mappedBy = "payment", cascade = { CascadeType.PERSIST, CascadeType.MERGE })
22 | private Order order;
23 |
24 | @NotBlank
25 | @Size(min = 4, message = "Payment method must contain at least 4 characters")
26 | private String paymentMethod;
27 |
28 | private String pgPaymentId;
29 | private String pgStatus;
30 | private String pgResponseMessage;
31 |
32 | private String pgName;
33 |
34 |
35 | public Payment(String paymentMethod, String pgPaymentId, String pgStatus,
36 | String pgResponseMessage, String pgName) {
37 | this.paymentMethod = paymentMethod;
38 | this.pgPaymentId = pgPaymentId;
39 | this.pgStatus = pgStatus;
40 | this.pgResponseMessage = pgResponseMessage;
41 | this.pgName = pgName;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/model/Product.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.model;
2 |
3 | import jakarta.persistence.*;
4 | import jakarta.validation.constraints.NotBlank;
5 | import jakarta.validation.constraints.Size;
6 | import lombok.AllArgsConstructor;
7 | import lombok.Data;
8 | import lombok.NoArgsConstructor;
9 | import lombok.ToString;
10 |
11 | import java.util.ArrayList;
12 | import java.util.List;
13 |
14 | @Entity
15 | @Data
16 | @NoArgsConstructor
17 | @AllArgsConstructor
18 | @Table(name = "products")
19 | @ToString
20 | public class Product {
21 |
22 | @Id
23 | @GeneratedValue(strategy = GenerationType.AUTO)
24 | private Long productId;
25 |
26 | @NotBlank
27 | @Size(min = 3, message = "Product name must contain atleast 3 characters")
28 | private String productName;
29 | private String image;
30 |
31 | @NotBlank
32 | @Size(min = 6, message = "Product description must contain atleast 6 characters")
33 | private String description;
34 | private Integer quantity;
35 | private double price;
36 | private double discount;
37 | private double specialPrice;
38 |
39 | @ManyToOne
40 | @JoinColumn(name = "category_id")
41 | private Category category;
42 |
43 | @ManyToOne
44 | @JoinColumn(name = "seller_id")
45 | private User user;
46 |
47 | @OneToMany(mappedBy = "product", cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.EAGER)
48 | private List products = new ArrayList<>();
49 | }
50 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/model/Role.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.model;
2 |
3 | import jakarta.persistence.*;
4 | import lombok.AllArgsConstructor;
5 | import lombok.Data;
6 | import lombok.NoArgsConstructor;
7 | import lombok.ToString;
8 |
9 | @Entity
10 | @NoArgsConstructor
11 | @AllArgsConstructor
12 | @Data
13 | @Table(name = "roles")
14 | public class Role {
15 |
16 | @Id
17 | @GeneratedValue(strategy = GenerationType.IDENTITY)
18 | @Column(name = "role_id")
19 | private Integer roleId;
20 |
21 | @ToString.Exclude
22 | @Enumerated(EnumType.STRING)
23 | @Column(length = 20, name = "role_name")
24 | private AppRole roleName;
25 |
26 | public Role(AppRole roleName) {
27 | this.roleName = roleName;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/model/User.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.model;
2 |
3 | import jakarta.persistence.*;
4 | import jakarta.validation.constraints.Email;
5 | import jakarta.validation.constraints.NotBlank;
6 | import jakarta.validation.constraints.Size;
7 | import lombok.*;
8 |
9 | import java.util.ArrayList;
10 | import java.util.HashSet;
11 | import java.util.List;
12 | import java.util.Set;
13 |
14 | @Entity
15 | @Data
16 | @NoArgsConstructor
17 | @Table(name = "users",
18 | uniqueConstraints = {
19 | @UniqueConstraint(columnNames = "username"),
20 | @UniqueConstraint(columnNames = "email")
21 | })
22 | public class User {
23 | @Id
24 | @GeneratedValue(strategy = GenerationType.IDENTITY)
25 | @Column(name = "user_id")
26 | private Long userId;
27 |
28 | @NotBlank
29 | @Size(max = 20)
30 | @Column(name = "username")
31 | private String userName;
32 |
33 | @NotBlank
34 | @Size(max = 50)
35 | @Email
36 | @Column(name = "email")
37 | private String email;
38 |
39 | @NotBlank
40 | @Size(max = 120)
41 | @Column(name = "password")
42 | private String password;
43 |
44 | public User(String userName, String email, String password) {
45 | this.userName = userName;
46 | this.email = email;
47 | this.password = password;
48 | }
49 |
50 | @Setter
51 | @Getter
52 | @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE},
53 | fetch = FetchType.EAGER)
54 | @JoinTable(name = "user_role",
55 | joinColumns = @JoinColumn(name = "user_id"),
56 | inverseJoinColumns = @JoinColumn(name = "role_id"))
57 | private Set roles = new HashSet<>();
58 |
59 | @Getter
60 | @Setter
61 | @OneToMany(mappedBy = "user", cascade = {CascadeType.PERSIST, CascadeType.MERGE}, orphanRemoval = true)
62 | // @JoinTable(name = "user_address",
63 | // joinColumns = @JoinColumn(name = "user_id"),
64 | // inverseJoinColumns = @JoinColumn(name = "address_id"))
65 | private List addresses = new ArrayList<>();
66 |
67 | @ToString.Exclude
68 | @OneToOne(mappedBy = "user", cascade = { CascadeType.PERSIST, CascadeType.MERGE}, orphanRemoval = true)
69 | private Cart cart;
70 |
71 | @ToString.Exclude
72 | @OneToMany(mappedBy = "user",
73 | cascade = {CascadeType.PERSIST, CascadeType.MERGE},
74 | orphanRemoval = true)
75 | private Set products;
76 | }
77 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/payload/APIResponse.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.payload;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | @Data
8 | @NoArgsConstructor
9 | @AllArgsConstructor
10 | public class APIResponse {
11 | public String message;
12 | private boolean status;
13 | }
14 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/payload/AddressDTO.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.payload;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | @Data
8 | @NoArgsConstructor
9 | @AllArgsConstructor
10 | public class AddressDTO {
11 | private Long addressId;
12 | private String street;
13 | private String buildingName;
14 | private String city;
15 | private String state;
16 | private String country;
17 | private String pincode;
18 | }
19 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/payload/CartDTO.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.payload;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | @Data
11 | @NoArgsConstructor
12 | @AllArgsConstructor
13 | public class CartDTO {
14 | private Long cartId;
15 | private Double totalPrice = 0.0;
16 | private List products = new ArrayList<>();
17 | }
18 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/payload/CartItemDTO.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.payload;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | @Data
8 | @NoArgsConstructor
9 | @AllArgsConstructor
10 | public class CartItemDTO {
11 | private Long productId;
12 | private Integer quantity;
13 | }
14 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/payload/CategoryDTO.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.payload;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | @Data
8 | @NoArgsConstructor
9 | @AllArgsConstructor
10 | public class CategoryDTO {
11 | private Long categoryId;
12 | private String categoryName;
13 | }
14 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/payload/CategoryResponse.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.payload;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | import java.util.List;
8 |
9 | @Data
10 | @NoArgsConstructor
11 | @AllArgsConstructor
12 | public class CategoryResponse {
13 | private List content;
14 | private Integer pageNumber;
15 | private Integer pageSize;
16 | private Long totalElements;
17 | private Integer totalPages;
18 | private boolean lastPage;
19 | }
20 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/payload/OrderDTO.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.payload;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | import java.time.LocalDate;
8 | import java.util.List;
9 |
10 | @Data
11 | @NoArgsConstructor
12 | @AllArgsConstructor
13 | public class OrderDTO {
14 | private Long orderId;
15 | private String email;
16 | private List orderItems;
17 | private LocalDate orderDate;
18 | private PaymentDTO payment;
19 | private Double totalAmount;
20 | private String orderStatus;
21 | private Long addressId;
22 | }
23 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/payload/OrderItemDTO.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.payload;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | @Data
8 | @NoArgsConstructor
9 | @AllArgsConstructor
10 | public class OrderItemDTO {
11 | private Long orderItemId;
12 | private ProductDTO product;
13 | private Integer quantity;
14 | private double discount;
15 | private double orderedProductPrice;
16 | }
17 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/payload/OrderRequestDTO.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.payload;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | @Data
8 | @NoArgsConstructor
9 | @AllArgsConstructor
10 | public class OrderRequestDTO {
11 | private Long addressId;
12 | private String paymentMethod;
13 | private String pgName;
14 | private String pgPaymentId;
15 | private String pgStatus;
16 | private String pgResponseMessage;
17 | }
18 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/payload/PaymentDTO.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.payload;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | @Data
8 | @NoArgsConstructor
9 | @AllArgsConstructor
10 | public class PaymentDTO {
11 | private Long paymentId;
12 | private String paymentMethod;
13 | private String pgPaymentId;
14 | private String pgStatus;
15 | private String pgResponseMessage;
16 | private String pgName;
17 | }
18 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/payload/ProductDTO.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.payload;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | @Data
8 | @NoArgsConstructor
9 | @AllArgsConstructor
10 | public class ProductDTO {
11 | private Long productId;
12 | private String productName;
13 | private String image;
14 | private String description;
15 | private Integer quantity;
16 | private double price;
17 | private double discount;
18 | private double specialPrice;
19 | }
20 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/payload/ProductResponse.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.payload;
2 |
3 | import lombok.AllArgsConstructor;
4 | import lombok.Data;
5 | import lombok.NoArgsConstructor;
6 |
7 | import java.util.List;
8 |
9 | @Data
10 | @NoArgsConstructor
11 | @AllArgsConstructor
12 | public class ProductResponse {
13 | private List content;
14 | private Integer pageNumber;
15 | private Integer pageSize;
16 | private Long totalElements;
17 | private Integer totalPages;
18 | private boolean lastPage;
19 | }
20 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/payload/StripePaymentDto.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.payload;
2 |
3 | import lombok.Data;
4 |
5 | @Data
6 | public class StripePaymentDto {
7 | private Long amount;
8 | private String currency;
9 | }
10 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/repositories/AddressRepository.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.repositories;
2 |
3 | import com.ecommerce.project.model.Address;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | public interface AddressRepository extends JpaRepository {
7 | }
8 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/repositories/CartItemRepository.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.repositories;
2 |
3 | import com.ecommerce.project.model.CartItem;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 | import org.springframework.data.jpa.repository.Modifying;
6 | import org.springframework.data.jpa.repository.Query;
7 |
8 | public interface CartItemRepository extends JpaRepository {
9 | @Query("SELECT ci FROM CartItem ci WHERE ci.cart.id = ?1 AND ci.product.id = ?2")
10 | CartItem findCartItemByProductIdAndCartId(Long cartId, Long productId);
11 |
12 | @Modifying
13 | @Query("DELETE FROM CartItem ci WHERE ci.cart.id = ?1 AND ci.product.id = ?2")
14 | void deleteCartItemByProductIdAndCartId(Long cartId, Long productId);
15 |
16 | @Modifying
17 | @Query("DELETE FROM CartItem ci WHERE ci.cart.id = ?1")
18 | void deleteAllByCartId(Long cartId);
19 | }
20 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/repositories/CartRepository.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.repositories;
2 |
3 | import com.ecommerce.project.model.Cart;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 | import org.springframework.data.jpa.repository.Query;
6 |
7 | import java.util.List;
8 |
9 | public interface CartRepository extends JpaRepository {
10 | @Query("SELECT c FROM Cart c WHERE c.user.email = ?1")
11 | Cart findCartByEmail(String email);
12 |
13 | @Query("SELECT c FROM Cart c WHERE c.user.email = ?1 AND c.id = ?2")
14 | Cart findCartByEmailAndCartId(String emailId, Long cartId);
15 |
16 | @Query("SELECT c FROM Cart c JOIN FETCH c.cartItems ci JOIN FETCH ci.product p WHERE p.id = ?1")
17 | List findCartsByProductId(Long productId);
18 | }
19 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/repositories/CategoryRepository.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.repositories;
2 |
3 | import com.ecommerce.project.model.Category;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 |
6 | public interface CategoryRepository extends JpaRepository {
7 | Category findByCategoryName(String categoryName);
8 | }
9 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/repositories/OrderItemRepository.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.repositories;
2 |
3 |
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 | import org.springframework.stereotype.Repository;
6 |
7 | import com.ecommerce.project.model.OrderItem;
8 |
9 | @Repository
10 | public interface OrderItemRepository extends JpaRepository {
11 |
12 | }
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/repositories/OrderRepository.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.repositories;
2 |
3 |
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 | import org.springframework.stereotype.Repository;
6 |
7 | import com.ecommerce.project.model.Order;
8 |
9 | @Repository
10 | public interface OrderRepository extends JpaRepository {
11 |
12 | }
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/repositories/PaymentRepository.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.repositories;
2 |
3 |
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 | import org.springframework.stereotype.Repository;
6 |
7 | import com.ecommerce.project.model.Payment;
8 |
9 | @Repository
10 | public interface PaymentRepository extends JpaRepository{
11 |
12 | }
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/repositories/ProductRepository.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.repositories;
2 |
3 | import com.ecommerce.project.model.Category;
4 | import com.ecommerce.project.model.Product;
5 | import org.springframework.data.domain.Page;
6 | import org.springframework.data.domain.Pageable;
7 | import org.springframework.data.jpa.repository.JpaRepository;
8 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
9 | import org.springframework.stereotype.Repository;
10 |
11 | @Repository
12 | public interface ProductRepository extends JpaRepository, JpaSpecificationExecutor {
13 | Page findByCategoryOrderByPriceAsc(Category category, Pageable pageDetails);
14 |
15 | Page findByProductNameLikeIgnoreCase(String keyword, Pageable pageDetails);
16 | }
17 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/repositories/RoleRepository.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.repositories;
2 |
3 | import com.ecommerce.project.model.AppRole;
4 | import com.ecommerce.project.model.Role;
5 | import org.springframework.data.jpa.repository.JpaRepository;
6 |
7 | import java.util.Optional;
8 |
9 | public interface RoleRepository extends JpaRepository {
10 | Optional findByRoleName(AppRole appRole);
11 | }
12 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/repositories/UserRepository.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.repositories;
2 |
3 | import com.ecommerce.project.model.User;
4 | import org.springframework.data.jpa.repository.JpaRepository;
5 | import org.springframework.stereotype.Repository;
6 |
7 | import java.util.Optional;
8 |
9 | @Repository
10 | public interface UserRepository extends JpaRepository {
11 |
12 | Optional findByUserName(String username);
13 |
14 | Boolean existsByUserName(String username);
15 |
16 | Boolean existsByEmail(String email);
17 | }
18 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/security/WebConfig.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.security;
2 |
3 | import org.springframework.beans.factory.annotation.Value;
4 | import org.springframework.context.annotation.Configuration;
5 | import org.springframework.web.servlet.config.annotation.CorsRegistry;
6 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
7 |
8 | @Configuration
9 | public class WebConfig implements WebMvcConfigurer {
10 |
11 | @Value("${frontend.url}")
12 | String frontEndUrl;
13 |
14 | @Override
15 | public void addCorsMappings(CorsRegistry registry) {
16 | registry.addMapping("/**")
17 | .allowedOrigins("http://localhost:3000", frontEndUrl)
18 | .allowedMethods("GET","POST","PUT","DELETE","OPTIONS")
19 | .allowedHeaders("*")
20 | .allowCredentials(true);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/security/jwt/AuthEntryPointJwt.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.security.jwt;
2 |
3 | import com.fasterxml.jackson.databind.ObjectMapper;
4 | import jakarta.servlet.ServletException;
5 | import jakarta.servlet.http.HttpServletRequest;
6 | import jakarta.servlet.http.HttpServletResponse;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 | import org.springframework.http.MediaType;
10 | import org.springframework.security.core.AuthenticationException;
11 | import org.springframework.security.web.AuthenticationEntryPoint;
12 | import org.springframework.stereotype.Component;
13 |
14 | import java.io.IOException;
15 | import java.util.HashMap;
16 | import java.util.Map;
17 |
18 | @Component
19 | public class AuthEntryPointJwt implements AuthenticationEntryPoint {
20 |
21 | private static final Logger logger = LoggerFactory.getLogger(AuthEntryPointJwt.class);
22 |
23 | @Override
24 | public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
25 | throws IOException, ServletException {
26 | logger.error("Unauthorized error: {}", authException.getMessage());
27 |
28 | response.setContentType(MediaType.APPLICATION_JSON_VALUE);
29 | response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
30 |
31 | final Map body = new HashMap<>();
32 | body.put("status", HttpServletResponse.SC_UNAUTHORIZED);
33 | body.put("error", "Unauthorized");
34 | body.put("message", authException.getMessage());
35 | body.put("path", request.getServletPath());
36 |
37 | final ObjectMapper mapper = new ObjectMapper();
38 | mapper.writeValue(response.getOutputStream(), body);
39 | }
40 |
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/security/jwt/AuthTokenFilter.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.security.jwt;
2 |
3 | import com.ecommerce.project.security.services.UserDetailsServiceImpl;
4 | import jakarta.servlet.FilterChain;
5 | import jakarta.servlet.ServletException;
6 | import jakarta.servlet.http.HttpServletRequest;
7 | import jakarta.servlet.http.HttpServletResponse;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 | import org.springframework.beans.factory.annotation.Autowired;
11 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
12 | import org.springframework.security.core.context.SecurityContextHolder;
13 | import org.springframework.security.core.userdetails.UserDetails;
14 | import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
15 | import org.springframework.stereotype.Component;
16 | import org.springframework.web.filter.OncePerRequestFilter;
17 |
18 | import java.io.IOException;
19 |
20 | @Component
21 | public class AuthTokenFilter extends OncePerRequestFilter {
22 | @Autowired
23 | private JwtUtils jwtUtils;
24 |
25 | @Autowired
26 | private UserDetailsServiceImpl userDetailsService;
27 |
28 | private static final Logger logger = LoggerFactory.getLogger(AuthTokenFilter.class);
29 |
30 | @Override
31 | protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
32 | throws ServletException, IOException {
33 | logger.debug("AuthTokenFilter called for URI: {}", request.getRequestURI());
34 | try {
35 | String jwt = parseJwt(request);
36 | if (jwt != null && jwtUtils.validateJwtToken(jwt)) {
37 | String username = jwtUtils.getUserNameFromJwtToken(jwt);
38 |
39 | UserDetails userDetails = userDetailsService.loadUserByUsername(username);
40 |
41 | UsernamePasswordAuthenticationToken authentication =
42 | new UsernamePasswordAuthenticationToken(userDetails,
43 | null,
44 | userDetails.getAuthorities());
45 | logger.debug("Roles from JWT: {}", userDetails.getAuthorities());
46 |
47 | authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
48 |
49 | SecurityContextHolder.getContext().setAuthentication(authentication);
50 | }
51 | } catch (Exception e) {
52 | logger.error("Cannot set user authentication: {}", e);
53 | }
54 |
55 | filterChain.doFilter(request, response);
56 | }
57 |
58 | private String parseJwt(HttpServletRequest request) {
59 | String jwt = jwtUtils.getJwtFromCookies(request);
60 | logger.debug("AuthTokenFilter.java: {}", jwt);
61 | return jwt;
62 | }
63 | }
64 |
65 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/security/jwt/JwtUtils.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.security.jwt;
2 |
3 | import com.ecommerce.project.security.services.UserDetailsImpl;
4 | import io.jsonwebtoken.*;
5 | import io.jsonwebtoken.io.Decoders;
6 | import io.jsonwebtoken.security.Keys;
7 | import jakarta.servlet.http.Cookie;
8 | import jakarta.servlet.http.HttpServletRequest;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 | import org.springframework.beans.factory.annotation.Value;
12 | import org.springframework.http.ResponseCookie;
13 | import org.springframework.security.core.userdetails.UserDetails;
14 | import org.springframework.stereotype.Component;
15 | import org.springframework.web.util.WebUtils;
16 |
17 | import javax.crypto.SecretKey;
18 | import java.security.Key;
19 | import java.util.Date;
20 |
21 | @Component
22 | public class JwtUtils {
23 | private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class);
24 |
25 | @Value("${spring.app.jwtSecret}")
26 | private String jwtSecret;
27 |
28 | @Value("${spring.app.jwtExpirationMs}")
29 | private int jwtExpirationMs;
30 |
31 | @Value("${spring.ecom.app.jwtCookieName}")
32 | private String jwtCookie;
33 |
34 | public String getJwtFromCookies(HttpServletRequest request) {
35 | Cookie cookie = WebUtils.getCookie(request, jwtCookie);
36 | if (cookie != null) {
37 | return cookie.getValue();
38 | } else {
39 | return null;
40 | }
41 | }
42 |
43 | public ResponseCookie generateJwtCookie(UserDetailsImpl userPrincipal) {
44 | String jwt = generateTokenFromUsername(userPrincipal.getUsername());
45 | ResponseCookie cookie = ResponseCookie.from(jwtCookie, jwt)
46 | .path("/api")
47 | .maxAge(24 * 60 * 60)
48 | .httpOnly(false)
49 | .secure(false)
50 | .build();
51 | return cookie;
52 | }
53 |
54 | public ResponseCookie getCleanJwtCookie() {
55 | ResponseCookie cookie = ResponseCookie.from(jwtCookie, null)
56 | .path("/api")
57 | .build();
58 | return cookie;
59 | }
60 |
61 | public String generateTokenFromUsername(String username) {
62 | return Jwts.builder()
63 | .subject(username)
64 | .issuedAt(new Date())
65 | .expiration(new Date((new Date()).getTime() + jwtExpirationMs))
66 | .signWith(key())
67 | .compact();
68 | }
69 |
70 | public String getUserNameFromJwtToken(String token) {
71 | return Jwts.parser()
72 | .verifyWith((SecretKey) key())
73 | .build().parseSignedClaims(token)
74 | .getPayload().getSubject();
75 | }
76 |
77 | private Key key() {
78 | return Keys.hmacShaKeyFor(Decoders.BASE64.decode(jwtSecret));
79 | }
80 |
81 | public boolean validateJwtToken(String authToken) {
82 | try {
83 | Jwts.parser().verifyWith((SecretKey) key()).build().parseSignedClaims(authToken);
84 | return true;
85 | } catch (MalformedJwtException e) {
86 | logger.error("Invalid JWT token: {}", e.getMessage());
87 | } catch (ExpiredJwtException e) {
88 | logger.error("JWT token is expired: {}", e.getMessage());
89 | } catch (UnsupportedJwtException e) {
90 | logger.error("JWT token is unsupported: {}", e.getMessage());
91 | } catch (IllegalArgumentException e) {
92 | logger.error("JWT claims string is empty: {}", e.getMessage());
93 | }
94 | return false;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/security/request/LoginRequest.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.security.request;
2 |
3 | import jakarta.validation.constraints.NotBlank;
4 |
5 | public class LoginRequest {
6 | @NotBlank
7 | private String username;
8 |
9 | @NotBlank
10 | private String password;
11 |
12 | public String getUsername() {
13 | return username;
14 | }
15 |
16 | public void setUsername(String username) {
17 | this.username = username;
18 | }
19 |
20 | public String getPassword() {
21 | return password;
22 | }
23 |
24 | public void setPassword(String password) {
25 | this.password = password;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/security/request/SignupRequest.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.security.request;
2 |
3 | import java.util.Set;
4 |
5 | import jakarta.validation.constraints.*;
6 | import lombok.Data;
7 |
8 | @Data
9 | public class SignupRequest {
10 | @NotBlank
11 | @Size(min = 3, max = 20)
12 | private String username;
13 |
14 | @NotBlank
15 | @Size(max = 50)
16 | @Email
17 | private String email;
18 |
19 | private Set role;
20 |
21 | @NotBlank
22 | @Size(min = 6, max = 40)
23 | private String password;
24 |
25 | public Set getRole() {
26 | return this.role;
27 | }
28 |
29 | public void setRole(Set role) {
30 | this.role = role;
31 | }
32 | }
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/security/response/MessageResponse.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.security.response;
2 |
3 | public class MessageResponse {
4 | private String message;
5 |
6 | public MessageResponse(String message) {
7 | this.message = message;
8 | }
9 |
10 | public String getMessage() {
11 | return message;
12 | }
13 |
14 | public void setMessage(String message) {
15 | this.message = message;
16 | }
17 | }
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/security/response/UserInfoResponse.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.security.response;
2 |
3 | import java.util.List;
4 |
5 | public class UserInfoResponse {
6 | private Long id;
7 | private String jwtToken;
8 | private String username;
9 | private List roles;
10 |
11 | public UserInfoResponse(Long id, String username, List roles, String jwtToken) {
12 | this.id = id;
13 | this.username = username;
14 | this.roles = roles;
15 | this.jwtToken = jwtToken;
16 | }
17 |
18 | public UserInfoResponse(Long id, String username, List roles) {
19 | this.id = id;
20 | this.username = username;
21 | this.roles = roles;
22 | }
23 |
24 | public Long getId() {
25 | return id;
26 | }
27 |
28 | public void setId(Long id) {
29 | this.id = id;
30 | }
31 |
32 | public String getJwtToken() {
33 | return jwtToken;
34 | }
35 |
36 | public void setJwtToken(String jwtToken) {
37 | this.jwtToken = jwtToken;
38 | }
39 |
40 | public String getUsername() {
41 | return username;
42 | }
43 |
44 | public void setUsername(String username) {
45 | this.username = username;
46 | }
47 |
48 | public List getRoles() {
49 | return roles;
50 | }
51 |
52 | public void setRoles(List roles) {
53 | this.roles = roles;
54 | }
55 | }
56 |
57 |
58 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/security/services/UserDetailsImpl.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.security.services;
2 |
3 | import java.util.Collection;
4 | import java.util.List;
5 | import java.util.Objects;
6 | import java.util.stream.Collectors;
7 |
8 | import lombok.Data;
9 | import lombok.NoArgsConstructor;
10 | import org.springframework.security.core.GrantedAuthority;
11 | import org.springframework.security.core.authority.SimpleGrantedAuthority;
12 | import org.springframework.security.core.userdetails.UserDetails;
13 |
14 | import com.ecommerce.project.model.User;
15 | import com.fasterxml.jackson.annotation.JsonIgnore;
16 |
17 | @NoArgsConstructor
18 | @Data
19 | public class UserDetailsImpl implements UserDetails {
20 | private static final long serialVersionUID = 1L;
21 |
22 | private Long id;
23 |
24 | private String username;
25 |
26 | private String email;
27 |
28 | @JsonIgnore
29 | private String password;
30 |
31 | private Collection extends GrantedAuthority> authorities;
32 |
33 | public UserDetailsImpl(Long id, String username, String email, String password,
34 | Collection extends GrantedAuthority> authorities) {
35 | this.id = id;
36 | this.username = username;
37 | this.email = email;
38 | this.password = password;
39 | this.authorities = authorities;
40 | }
41 |
42 | public static UserDetailsImpl build(User user) {
43 | List authorities = user.getRoles().stream()
44 | .map(role -> new SimpleGrantedAuthority(role.getRoleName().name()))
45 | .collect(Collectors.toList());
46 |
47 | return new UserDetailsImpl(
48 | user.getUserId(),
49 | user.getUserName(),
50 | user.getEmail(),
51 | user.getPassword(),
52 | authorities);
53 | }
54 |
55 | @Override
56 | public Collection extends GrantedAuthority> getAuthorities() {
57 | return authorities;
58 | }
59 |
60 | public Long getId() {
61 | return id;
62 | }
63 |
64 | public String getEmail() {
65 | return email;
66 | }
67 |
68 | @Override
69 | public String getPassword() {
70 | return password;
71 | }
72 |
73 | @Override
74 | public String getUsername() {
75 | return username;
76 | }
77 |
78 | @Override
79 | public boolean isAccountNonExpired() {
80 | return true;
81 | }
82 |
83 | @Override
84 | public boolean isAccountNonLocked() {
85 | return true;
86 | }
87 |
88 | @Override
89 | public boolean isCredentialsNonExpired() {
90 | return true;
91 | }
92 |
93 | @Override
94 | public boolean isEnabled() {
95 | return true;
96 | }
97 |
98 | @Override
99 | public boolean equals(Object o) {
100 | if (this == o)
101 | return true;
102 | if (o == null || getClass() != o.getClass())
103 | return false;
104 | UserDetailsImpl user = (UserDetailsImpl) o;
105 | return Objects.equals(id, user.id);
106 | }
107 |
108 | }
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/security/services/UserDetailsServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.security.services;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.security.core.Authentication;
5 | import org.springframework.security.core.context.SecurityContextHolder;
6 | import org.springframework.security.core.userdetails.UserDetails;
7 | import org.springframework.security.core.userdetails.UserDetailsService;
8 | import org.springframework.security.core.userdetails.UsernameNotFoundException;
9 | import org.springframework.stereotype.Service;
10 | import org.springframework.transaction.annotation.Transactional;
11 |
12 | import com.ecommerce.project.model.User;
13 | import com.ecommerce.project.repositories.UserRepository;
14 |
15 | @Service
16 | public class UserDetailsServiceImpl implements UserDetailsService {
17 | @Autowired
18 | UserRepository userRepository;
19 |
20 | @Override
21 | @Transactional
22 | public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
23 | User user = userRepository.findByUserName(username)
24 | .orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + username));
25 |
26 | return UserDetailsImpl.build(user);
27 | }
28 |
29 |
30 | }
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/service/AddressService.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.service;
2 |
3 | import com.ecommerce.project.model.User;
4 | import com.ecommerce.project.payload.AddressDTO;
5 |
6 | import java.util.List;
7 |
8 | public interface AddressService {
9 | AddressDTO createAddress(AddressDTO addressDTO, User user);
10 |
11 | List getAddresses();
12 |
13 | AddressDTO getAddressesById(Long addressId);
14 |
15 | List getUserAddresses(User user);
16 |
17 | AddressDTO updateAddress(Long addressId, AddressDTO addressDTO);
18 |
19 | String deleteAddress(Long addressId);
20 | }
21 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/service/CartService.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.service;
2 |
3 | import com.ecommerce.project.payload.CartDTO;
4 | import com.ecommerce.project.payload.CartItemDTO;
5 | import jakarta.transaction.Transactional;
6 |
7 | import java.util.List;
8 |
9 | public interface CartService {
10 | CartDTO addProductToCart(Long productId, Integer quantity);
11 |
12 | List getAllCarts();
13 |
14 | CartDTO getCart(String emailId, Long cartId);
15 |
16 | @Transactional
17 | CartDTO updateProductQuantityInCart(Long productId, Integer quantity);
18 |
19 | String deleteProductFromCart(Long cartId, Long productId);
20 |
21 | void updateProductInCarts(Long cartId, Long productId);
22 |
23 | String createOrUpdateCartWithItems(List cartItems);
24 | }
25 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/service/CategoryService.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.service;
2 |
3 | import com.ecommerce.project.model.Category;
4 | import com.ecommerce.project.payload.CategoryDTO;
5 | import com.ecommerce.project.payload.CategoryResponse;
6 |
7 | public interface CategoryService {
8 | CategoryResponse getAllCategories(Integer pageNumber, Integer pageSize, String sortBy, String sortOrder);
9 | CategoryDTO createCategory(CategoryDTO categoryDTO);
10 |
11 | CategoryDTO deleteCategory(Long categoryId);
12 |
13 | CategoryDTO updateCategory(CategoryDTO categoryDTO, Long categoryId);
14 | }
15 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/service/FileService.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.service;
2 |
3 | import org.springframework.web.multipart.MultipartFile;
4 |
5 | import java.io.IOException;
6 |
7 | public interface FileService {
8 | String uploadImage(String path, MultipartFile file) throws IOException;
9 | }
10 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/service/FileServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.service;
2 |
3 | import org.springframework.stereotype.Service;
4 | import org.springframework.web.multipart.MultipartFile;
5 |
6 | import java.io.File;
7 | import java.io.IOException;
8 | import java.nio.file.Files;
9 | import java.nio.file.Paths;
10 | import java.util.UUID;
11 |
12 | @Service
13 | public class FileServiceImpl implements FileService {
14 |
15 | @Override
16 | public String uploadImage(String path, MultipartFile file) throws IOException {
17 | String originalFileName = file.getOriginalFilename();
18 | String randomId = UUID.randomUUID().toString();
19 | String fileName = randomId.concat(originalFileName.substring(originalFileName.lastIndexOf('.')));
20 | String filePath = path + File.separator + fileName;
21 |
22 | File folder = new File(path);
23 | if (!folder.exists())
24 | folder.mkdir();
25 |
26 | Files.copy(file.getInputStream(), Paths.get(filePath));
27 | return fileName;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/service/OrderService.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.service;
2 |
3 | import com.ecommerce.project.payload.OrderDTO;
4 | import jakarta.transaction.Transactional;
5 |
6 | public interface OrderService {
7 | @Transactional
8 | OrderDTO placeOrder(String emailId, Long addressId, String paymentMethod, String pgName, String pgPaymentId, String pgStatus, String pgResponseMessage);
9 | }
10 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/service/ProductService.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.service;
2 |
3 | import com.ecommerce.project.payload.ProductDTO;
4 | import com.ecommerce.project.payload.ProductResponse;
5 | import org.springframework.web.multipart.MultipartFile;
6 |
7 | import java.io.IOException;
8 |
9 | public interface ProductService {
10 | ProductDTO addProduct(Long categoryId, ProductDTO product);
11 |
12 | ProductResponse getAllProducts(Integer pageNumber, Integer pageSize, String sortBy, String sortOrder, String keyword, String category);
13 |
14 | ProductResponse searchByCategory(Long categoryId, Integer pageNumber, Integer pageSize, String sortBy, String sortOrder);
15 |
16 | ProductResponse searchProductByKeyword(String keyword, Integer pageNumber, Integer pageSize, String sortBy, String sortOrder);
17 |
18 | ProductDTO updateProduct(Long productId, ProductDTO product);
19 |
20 | ProductDTO deleteProduct(Long productId);
21 |
22 | ProductDTO updateProductImage(Long productId, MultipartFile image) throws IOException;
23 | }
24 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/service/StripeService.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.service;
2 |
3 | import com.ecommerce.project.payload.StripePaymentDto;
4 | import com.stripe.exception.StripeException;
5 | import com.stripe.model.PaymentIntent;
6 |
7 | public interface StripeService {
8 |
9 | PaymentIntent paymentIntent(StripePaymentDto stripePaymentDto) throws StripeException;
10 | }
11 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/service/StripeServiceImpl.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.service;
2 |
3 | import com.ecommerce.project.payload.StripePaymentDto;
4 | import com.stripe.Stripe;
5 | import com.stripe.exception.StripeException;
6 | import com.stripe.model.PaymentIntent;
7 | import com.stripe.param.PaymentIntentCreateParams;
8 | import jakarta.annotation.PostConstruct;
9 | import jakarta.transaction.Transactional;
10 | import org.springframework.beans.factory.annotation.Value;
11 | import org.springframework.stereotype.Service;
12 |
13 | @Service
14 | @Transactional
15 | public class StripeServiceImpl implements StripeService {
16 |
17 | @Value("${stripe.secret.key}")
18 | private String stripeApiKey;
19 |
20 | @PostConstruct
21 | public void init(){
22 | Stripe.apiKey = stripeApiKey;
23 | }
24 |
25 | @Override
26 | public PaymentIntent paymentIntent(StripePaymentDto stripePaymentDto) throws StripeException {
27 | PaymentIntentCreateParams params =
28 | PaymentIntentCreateParams.builder()
29 | .setAmount(stripePaymentDto.getAmount())
30 | .setCurrency(stripePaymentDto.getCurrency())
31 | .setAutomaticPaymentMethods(
32 | PaymentIntentCreateParams.AutomaticPaymentMethods.builder()
33 | .setEnabled(true)
34 | .build()
35 | )
36 | .build();
37 |
38 | return PaymentIntent.create(params);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/sb-ecom/src/main/java/com/ecommerce/project/util/AuthUtil.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project.util;
2 |
3 | import com.ecommerce.project.model.User;
4 | import com.ecommerce.project.repositories.UserRepository;
5 | import org.springframework.beans.factory.annotation.Autowired;
6 | import org.springframework.security.core.Authentication;
7 | import org.springframework.security.core.context.SecurityContextHolder;
8 | import org.springframework.security.core.userdetails.UsernameNotFoundException;
9 | import org.springframework.stereotype.Component;
10 |
11 | @Component
12 | public class AuthUtil {
13 |
14 | @Autowired
15 | UserRepository userRepository;
16 |
17 | public String loggedInEmail(){
18 | Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
19 | User user = userRepository.findByUserName(authentication.getName())
20 | .orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + authentication.getName()));
21 |
22 | return user.getEmail();
23 | }
24 |
25 | public Long loggedInUserId(){
26 | Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
27 | User user = userRepository.findByUserName(authentication.getName())
28 | .orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + authentication.getName()));
29 |
30 | return user.getUserId();
31 | }
32 |
33 | public User loggedInUser(){
34 | Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
35 |
36 | User user = userRepository.findByUserName(authentication.getName())
37 | .orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + authentication.getName()));
38 | return user;
39 |
40 | }
41 |
42 |
43 | }
--------------------------------------------------------------------------------
/sb-ecom/src/main/resources/application.properties:
--------------------------------------------------------------------------------
1 | spring.application.name=sb-ecom
2 |
3 | spring.datasource.url=jdbc:postgresql://localhost:5432/ecommerce
4 | spring.datasource.username=postgres
5 | spring.datasource.password=admin@123
6 |
7 | spring.jpa.hibernate.ddl-auto=update
8 | spring.jpa.database-platform=org.hibernate.dialect.PostgreSQLDialect
9 |
10 | #spring.h2.console.enabled=true
11 | #spring.datasource.url=jdbc:h2:mem:test
12 |
13 | project.image=images/
14 |
15 | #spring.jpa.show-sql=true
16 | #spring.jpa.properties.hibernate.format_sql=true
17 |
18 |
19 | spring.app.jwtSecret=mySecretKey123912738aopsgjnspkmndfsopkvajoirjg94gf2opfng2moknm
20 | spring.app.jwtExpirationMs=300000000
21 | spring.ecom.app.jwtCookieName=springBootEcom
22 |
23 |
24 |
25 | logging.level.org.springframework=DEBUG
26 | logging.level.org.hibernate.SQL=DEBUG
27 | logging.level.org.springframework.security=DEBUG
28 | logging.level.com.ecommerce.project=DEBUG
29 |
30 |
31 | # Needed if you are using elastic beanstalk
32 | #server.port=5000
33 | frontend.url=http://localhost:5173/
34 | image.base.url=http://localhost:8080/images
35 |
36 | #STRIPE KEY
37 | stripe.secret.key=${STRIPE_SECRET_KEY}
38 |
--------------------------------------------------------------------------------
/sb-ecom/src/test/java/com/ecommerce/project/SbEcomApplicationTests.java:
--------------------------------------------------------------------------------
1 | package com.ecommerce.project;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.springframework.boot.test.context.SpringBootTest;
5 |
6 | @SpringBootTest
7 | class SbEcomApplicationTests {
8 |
9 | @Test
10 | void contextLoads() {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------