diff --git a/src/main/frontend/generated/theme.d.ts b/src/main/frontend/generated/theme.d.ts new file mode 100644 index 0000000..94ce92d --- /dev/null +++ b/src/main/frontend/generated/theme.d.ts @@ -0,0 +1 @@ +export declare const applyTheme: (target: Node) => void; \ No newline at end of file diff --git a/src/main/frontend/generated/theme.js b/src/main/frontend/generated/theme.js new file mode 100644 index 0000000..52ce319 --- /dev/null +++ b/src/main/frontend/generated/theme.js @@ -0,0 +1,2 @@ +import {applyTheme as _applyTheme} from './theme-my-theme.generated.js'; +export const applyTheme = _applyTheme; diff --git a/src/main/frontend/generated/vaadin.ts b/src/main/frontend/generated/vaadin.ts index d38f466..aabe079 100644 --- a/src/main/frontend/generated/vaadin.ts +++ b/src/main/frontend/generated/vaadin.ts @@ -35,3 +35,7 @@ import './index'; import './vaadin-react.js'; import 'Frontend/generated/jar-resources/vaadin-dev-tools/vaadin-dev-tools.js'; + +import './theme-my-theme.global.generated.js'; +import { applyTheme } from './theme.js'; +applyTheme(document); diff --git a/src/main/frontend/themes/my-theme/styles.css b/src/main/frontend/themes/my-theme/styles.css new file mode 100644 index 0000000..e69de29 diff --git a/src/main/java/io/bcn/springConference/SpringConferenceApplication.java b/src/main/java/io/bcn/springConference/SpringConferenceApplication.java index 85c0fb5..59f0a35 100644 --- a/src/main/java/io/bcn/springConference/SpringConferenceApplication.java +++ b/src/main/java/io/bcn/springConference/SpringConferenceApplication.java @@ -2,12 +2,14 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import com.vaadin.flow.theme.Theme; +import com.vaadin.flow.component.page.AppShellConfigurator; @SpringBootApplication -public class SpringConferenceApplication { - - public static void main(String[] args) { - SpringApplication.run(SpringConferenceApplication.class, args); - } +@Theme("my-theme") +public class SpringConferenceApplication implements AppShellConfigurator { + public static void main(String[] args) { + SpringApplication.run(SpringConferenceApplication.class, args); + } } diff --git a/src/main/java/io/bcn/springConference/model/Book.java b/src/main/java/io/bcn/springConference/model/Book.java index 5638c89..dd8fb84 100644 --- a/src/main/java/io/bcn/springConference/model/Book.java +++ b/src/main/java/io/bcn/springConference/model/Book.java @@ -6,6 +6,9 @@ import lombok.NoArgsConstructor; import lombok.Setter; import org.hibernate.annotations.GenericGenerator; + +import java.util.ArrayList; +import java.util.List; import java.util.UUID; @@ -16,24 +19,22 @@ @NoArgsConstructor @AllArgsConstructor public class Book { - @Id @GeneratedValue(generator = "UUID") - @GenericGenerator(name = "UUID", - strategy = "org.hibernate.id.UUIDGenerator") - @Column(name = "id", updatable = false, - nullable = false) + @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") + @Column private UUID id; - @Column(nullable = false) + @Column private String title; - @Column(nullable = false) + @Column private String author; - @Column(nullable = false, unique = true) + @Column private String ISBN; -/* @OneToMany(mappedBy = "book") - private List conferences;*/ + @OneToMany(mappedBy = "book") + private List conferences = new ArrayList<>(); } + diff --git a/src/main/java/io/bcn/springConference/model/Conference.java b/src/main/java/io/bcn/springConference/model/Conference.java index 15d79d2..cdd357c 100644 --- a/src/main/java/io/bcn/springConference/model/Conference.java +++ b/src/main/java/io/bcn/springConference/model/Conference.java @@ -1,4 +1,41 @@ package io.bcn.springConference.model; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.annotations.GenericGenerator; + +import java.time.LocalDate; +import java.util.Date; +import java.util.UUID; + +@Entity +@Table(name = "conferences") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor public class Conference { + @Id + @GeneratedValue(generator = "UUID") + @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") + @Column + private UUID id; + + @Column + private String name; + + @Column + private LocalDate date; + + @ManyToOne + @JoinColumn(name = "book_id") + private Book book; + + @ManyToOne + @JoinColumn(name = "speaker_id") + private Speaker speaker; } + diff --git a/src/main/java/io/bcn/springConference/model/Speaker.java b/src/main/java/io/bcn/springConference/model/Speaker.java index db76a55..409cd4e 100644 --- a/src/main/java/io/bcn/springConference/model/Speaker.java +++ b/src/main/java/io/bcn/springConference/model/Speaker.java @@ -1,4 +1,32 @@ package io.bcn.springConference.model; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.annotations.GenericGenerator; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@Entity +@Table(name = "speakers") +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor public class Speaker { + @Id + @GeneratedValue(generator = "UUID") + @GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator") + @Column + private UUID id; + + @Column + private String name; + + @OneToMany(mappedBy = "speaker") + private List conferences = new ArrayList<>(); } diff --git a/src/main/java/io/bcn/springConference/repository/ConferenceRepository.java b/src/main/java/io/bcn/springConference/repository/ConferenceRepository.java new file mode 100644 index 0000000..36c09f4 --- /dev/null +++ b/src/main/java/io/bcn/springConference/repository/ConferenceRepository.java @@ -0,0 +1,8 @@ +package io.bcn.springConference.repository; + +import io.bcn.springConference.model.Conference; +import org.springframework.data.jpa.repository.JpaRepository; +import java.util.UUID; + +public interface ConferenceRepository extends JpaRepository { +} diff --git a/src/main/java/io/bcn/springConference/repository/SpeakerRepository.java b/src/main/java/io/bcn/springConference/repository/SpeakerRepository.java new file mode 100644 index 0000000..c4d6e97 --- /dev/null +++ b/src/main/java/io/bcn/springConference/repository/SpeakerRepository.java @@ -0,0 +1,8 @@ +package io.bcn.springConference.repository; + +import io.bcn.springConference.model.Speaker; +import org.springframework.data.jpa.repository.JpaRepository; +import java.util.UUID; + +public interface SpeakerRepository extends JpaRepository { +} diff --git a/src/main/java/io/bcn/springConference/view/ConferenceView.java b/src/main/java/io/bcn/springConference/view/ConferenceView.java index 4e99b93..7202229 100644 --- a/src/main/java/io/bcn/springConference/view/ConferenceView.java +++ b/src/main/java/io/bcn/springConference/view/ConferenceView.java @@ -1,74 +1,87 @@ -/* - package io.bcn.springConference.view; -import com.vaadin.flow.component.Component; +import com.vaadin.flow.component.avatar.Avatar; import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.combobox.ComboBox; +import com.vaadin.flow.component.datepicker.DatePicker; import com.vaadin.flow.component.grid.Grid; -import com.vaadin.flow.component.html.H2; -import com.vaadin.flow.component.orderedlayout.HorizontalLayout; import com.vaadin.flow.component.orderedlayout.VerticalLayout; -import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.data.binder.Binder; import com.vaadin.flow.router.Route; - - -@Route("/conference") +import io.bcn.springConference.model.Book; +import io.bcn.springConference.model.Conference; +import io.bcn.springConference.model.Speaker; +import io.bcn.springConference.repository.BookRepository; +import io.bcn.springConference.repository.ConferenceRepository; +import io.bcn.springConference.repository.SpeakerRepository; +import org.springframework.beans.factory.annotation.Autowired; + +@Route(value = "conferences", layout = MainLayout.class) public class ConferenceView extends VerticalLayout { + private final ConferenceRepository conferenceRepository; + private final BookRepository bookRepository; + private final SpeakerRepository speakerRepository; + private Grid grid = new Grid<>(Conference.class); + private Binder binder = new Binder<>(Conference.class); - private final TextField name = new TextField("Name"); - private final TextField email = new TextField("Email"); - private final TextField phoneNumber = new TextField("Phone Number"); - private final Button save = new Button("Save"); - private final Button delete = new Button("Delete"); - - - + private ComboBox bookComboBox; + private ComboBox speakerComboBox; + private DatePicker datePicker; + private Button saveButton; - // Method to create the main layout - private Component createMainLayout() { - // Create the 3-column layout - HorizontalLayout mainLayout = new HorizontalLayout(); - mainLayout.setSizeFull(); - mainLayout.setPadding(false); - mainLayout.setSpacing(false); + @Autowired + public ConferenceView(ConferenceRepository conferenceRepository, BookRepository bookRepository, SpeakerRepository speakerRepository) { + this.conferenceRepository = conferenceRepository; + this.bookRepository = bookRepository; + this.speakerRepository = speakerRepository; - // Left column (empty for spacing) - VerticalLayout leftColumn = new VerticalLayout(); - leftColumn.setWidth("20%"); + setupForm(); + setupGrid(); + add(grid, bookComboBox, speakerComboBox, datePicker, saveButton); + updateGrid(); + } - // Center column (contains all the components) - VerticalLayout centerColumn = new VerticalLayout(); - centerColumn.setWidth("60%"); - centerColumn.setAlignItems(Alignment.CENTER); + private void setupForm() { + bookComboBox = new ComboBox<>("Select Book"); + bookComboBox.setItems(bookRepository.findAll()); + bookComboBox.setItemLabelGenerator(Book::getTitle); - // Right column (empty for spacing) - VerticalLayout rightColumn = new VerticalLayout(); - rightColumn.setWidth("20%"); + speakerComboBox = new ComboBox<>("Select Speaker"); + speakerComboBox.setItems(speakerRepository.findAll()); + speakerComboBox.setItemLabelGenerator(Speaker::getName); - // Create a form layout - HorizontalLayout formLayout = new HorizontalLayout(name, email, phoneNumber); - formLayout.setWidth("100%"); - formLayout.setJustifyContentMode(JustifyContentMode.CENTER); + datePicker = new DatePicker("Date"); - // Create a button layout - HorizontalLayout buttonLayout = new HorizontalLayout(save, delete); - buttonLayout.setJustifyContentMode(JustifyContentMode.CENTER); + saveButton = new Button("Save", e -> saveConference()); - // Add components to the center column - centerColumn.add( - new H2("Customer Management"), - formLayout, - buttonLayout - ); + binder.bind(bookComboBox, Conference::getBook, Conference::setBook); + binder.bind(speakerComboBox, Conference::getSpeaker, Conference::setSpeaker); + binder.bind(datePicker, Conference::getDate, Conference::setDate); + } - // Add all columns to the main layout - mainLayout.add(leftColumn, centerColumn, rightColumn); + private void setupGrid() { + grid.setColumns("name", "date"); + grid.addComponentColumn(conference -> { + Speaker speaker = conference.getSpeaker(); + Avatar avatar = new Avatar(speaker.getName()); + avatar.setWidth("50px"); + avatar.setHeight("50px"); + return avatar; + }).setHeader("Speaker Avatar"); + } - return mainLayout; + private void saveConference() { + Conference conference = new Conference(); + binder.writeBeanIfValid(conference); + conferenceRepository.save(conference); + updateGrid(); + binder.readBean(null); } + private void updateGrid() { + grid.setItems(conferenceRepository.findAll()); + } } -*/ + diff --git a/src/main/java/io/bcn/springConference/view/HomeView.java b/src/main/java/io/bcn/springConference/view/HomeView.java new file mode 100644 index 0000000..09d4380 --- /dev/null +++ b/src/main/java/io/bcn/springConference/view/HomeView.java @@ -0,0 +1,14 @@ +package io.bcn.springConference.view; + +import com.vaadin.flow.component.html.Label; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.router.Route; + +@Route(value = "", layout = MainLayout.class) // Sets root URL to this view +public class HomeView extends VerticalLayout { + + public HomeView() { + add(new Label("Welcome to the Spring Conference Management Application!")); + add(new Label("Use the navigation links above to access Conferences and Speakers.")); + } +} diff --git a/src/main/java/io/bcn/springConference/view/MainLayout.java b/src/main/java/io/bcn/springConference/view/MainLayout.java new file mode 100644 index 0000000..73d0d28 --- /dev/null +++ b/src/main/java/io/bcn/springConference/view/MainLayout.java @@ -0,0 +1,23 @@ +package io.bcn.springConference.view; + +import com.vaadin.flow.component.applayout.AppLayout; +import com.vaadin.flow.component.orderedlayout.HorizontalLayout; +import com.vaadin.flow.router.RouterLink; + +public class MainLayout extends AppLayout { + + public MainLayout() { + createHeader(); + } + + private void createHeader() { + HorizontalLayout header = new HorizontalLayout(); + + RouterLink conferenceLink = new RouterLink("Conferences", ConferenceView.class); + RouterLink speakerLink = new RouterLink("Speakers", SpeakerView.class); + + header.add(conferenceLink, speakerLink); + addToNavbar(header); + } +} + diff --git a/src/main/java/io/bcn/springConference/view/SpeakerView.java b/src/main/java/io/bcn/springConference/view/SpeakerView.java new file mode 100644 index 0000000..fa2a863 --- /dev/null +++ b/src/main/java/io/bcn/springConference/view/SpeakerView.java @@ -0,0 +1,62 @@ +package io.bcn.springConference.view; + +import com.vaadin.flow.component.avatar.Avatar; +import com.vaadin.flow.component.button.Button; +import com.vaadin.flow.component.grid.Grid; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.component.textfield.TextField; +import com.vaadin.flow.data.binder.Binder; +import com.vaadin.flow.router.Route; +import io.bcn.springConference.model.Speaker; +import io.bcn.springConference.repository.SpeakerRepository; +import org.springframework.beans.factory.annotation.Autowired; + +@Route(value = "speakers", layout = MainLayout.class) +public class SpeakerView extends VerticalLayout { + + private final SpeakerRepository speakerRepository; + private Grid grid = new Grid<>(Speaker.class); + private Binder binder = new Binder<>(Speaker.class); + + private TextField nameField; + private Button saveButton; + + @Autowired + public SpeakerView(SpeakerRepository speakerRepository) { + this.speakerRepository = speakerRepository; + + setupForm(); + setupGrid(); + add(grid, nameField, saveButton); + updateGrid(); + } + + private void setupForm() { + nameField = new TextField("Speaker Name"); + saveButton = new Button("Save", e -> saveSpeaker()); + + binder.bind(nameField, Speaker::getName, Speaker::setName); + } + + private void setupGrid() { + grid.addComponentColumn(speaker -> { + Avatar avatar = new Avatar(speaker.getName(), "Avatar"); + avatar.setWidth("50px"); + avatar.setHeight("50px"); + return avatar; + }).setHeader("Avatar"); + grid.setColumns("name"); + } + + private void saveSpeaker() { + Speaker speaker = new Speaker(); + binder.writeBeanIfValid(speaker); + speakerRepository.save(speaker); + updateGrid(); + binder.readBean(null); + } + + private void updateGrid() { + grid.setItems(speakerRepository.findAll()); + } +} diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties index 2298f56..bbe1da1 100644 --- a/src/main/resources/application-local.properties +++ b/src/main/resources/application-local.properties @@ -1,6 +1,7 @@ # H2 LOCAL DB SERVER -spring.datasource.url=jdbc:h2:/home/albert/MyProjects/DataBase/conference/conferenceDB -spring.datasource.username=albert +#spring.datasource.url=jdbc:h2:/home/emma/MyProjects/DataBase/conference/conferenceDB +spring.datasource.url=jdbc:h2:/Users/Emma/Documents/code/java/DataBases/conferenceDB +spring.datasource.username=emma spring.datasource.password=1234 # DDL OPTIONS: create-drop, create, update, none, validate diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index 42ace5a..48d2be7 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -3,4 +3,15 @@ INSERT INTO books (id, title, author, isbn) VALUES (RANDOM_UUID(), 'Spring Boot in Action', 'Craig Walls', '9781617292545'), (RANDOM_UUID(), 'Spring Security in Action', 'Laurentiu Spilca', '9781617297731'), (RANDOM_UUID(), 'Reactive Spring', 'Josh Long', '9781732910225'), -(RANDOM_UUID(), 'Native Image Definitive Guide', 'Oleg Šelajev', '9781492078531'); \ No newline at end of file +(RANDOM_UUID(), 'Native Image Definitive Guide', 'Oleg Šelajev', '9781492078531'); + +INSERT INTO speakers (id, name) VALUES +(RANDOM_UUID(), 'Brandon Sanderson'), +(RANDOM_UUID(), 'Uncle Bob'), +(RANDOM_UUID(), 'Ada Lovelace'); + +--Error: Failed to execute SQL script statement #3 of class path resource [data.sql]: INSERT INTO conferences (id, name, conferenceDate) VALUES (RANDOM_UUID(), 'Spring Boot 101', '2025-03-20') +-- possibly LocalDate issue +--INSERT INTO conferences (id, name, date) VALUES +--(RANDOM_UUID(), 'Spring Boot 101', '2025-03-20'); +--(RANDOM_UUID(), 'Spring Boot Is Awesome', '2025-03-22'); \ No newline at end of file