diff --git a/pom.xml b/pom.xml index 5875d5ae..25ea50bf 100644 --- a/pom.xml +++ b/pom.xml @@ -1,52 +1,41 @@ - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 + http://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 - edu.csc207 - ca-login-example + org.example + testingapi 1.0-SNAPSHOT + + 17 + 17 + + + + + com.squareup.okhttp3 + okhttp + 4.12.0 + + org.json json 20240303 + - com.squareup.okhttp3 - okhttp - 4.12.0 - - - org.junit.jupiter - junit-jupiter - 5.8.1 - test + org.xerial + sqlite-jdbc + 3.45.2.0 - - - - - org.apache.maven.plugins - maven-compiler-plugin - - 15 - 15 - - - - - - - 11 - 11 - UTF-8 - + - \ No newline at end of file diff --git a/src/main/java/app/AddPetAppBuilder.java b/src/main/java/app/AddPetAppBuilder.java new file mode 100644 index 00000000..2a27ce24 --- /dev/null +++ b/src/main/java/app/AddPetAppBuilder.java @@ -0,0 +1,53 @@ +package app; + +import data_access.InMemoryPetDataAccessObject; +import entity.PetFactory; +import interface_adapter.add_pet.AddPetController; +import interface_adapter.add_pet.AddPetPresenter; +import interface_adapter.add_pet.AddPetView; +import interface_adapter.add_pet.AddPetViewModel; +import use_case.add_pet.AddPetDataAccessInterface; +import use_case.add_pet.AddPetInputBoundary; +import use_case.add_pet.AddPetInteractor; +import use_case.add_pet.AddPetOutputBoundary; + +import javax.swing.*; + +public class AddPetAppBuilder { + + private AddPetView addPetView; + private AddPetController addPetController; + + public AddPetAppBuilder addAddPetView() { + this.addPetView = new AddPetView(); + return this; + } + + public AddPetAppBuilder addAddPetUseCase() { + + AddPetDataAccessInterface petRepo = new InMemoryPetDataAccessObject(); + + AddPetViewModel addPetViewModel = new AddPetViewModel(); + AddPetOutputBoundary presenter = new AddPetPresenter(addPetViewModel); + + PetFactory petFactory = new PetFactory(); + + AddPetInputBoundary interactor = + new AddPetInteractor(petFactory, petRepo, presenter); + + this.addPetController = new AddPetController(interactor); + this.addPetView.setViewModel(addPetViewModel); + this.addPetView.setAddPetController(addPetController); + + return this; + } + + public JFrame build() { + JFrame frame = new JFrame("Add Pet"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setContentPane(addPetView); + return frame; + } +} + + diff --git a/src/main/java/app/AddPetMain.java b/src/main/java/app/AddPetMain.java new file mode 100644 index 00000000..1d8fc97d --- /dev/null +++ b/src/main/java/app/AddPetMain.java @@ -0,0 +1,22 @@ +package app; + +import app.AddPetAppBuilder; + +import javax.swing.*; + +public class AddPetMain { + public static void main(String[] args) { + + AddPetAppBuilder builder = new AddPetAppBuilder(); + + JFrame app = builder + .addAddPetView() + .addAddPetUseCase() + .build(); + + app.pack(); + app.setLocationRelativeTo(null); + app.setVisible(true); + } +} + diff --git a/src/main/java/app/AppBuilder.java b/src/main/java/app/AppBuilder.java index 3c654cad..5fbd0a92 100644 --- a/src/main/java/app/AppBuilder.java +++ b/src/main/java/app/AppBuilder.java @@ -11,6 +11,7 @@ import interface_adapter.login.LoginViewModel; import interface_adapter.logout.LogoutController; import interface_adapter.logout.LogoutPresenter; +import interface_adapter.manage_application.ManageApplicationViewModel; import interface_adapter.signup.SignupController; import interface_adapter.signup.SignupPresenter; import interface_adapter.signup.SignupViewModel; @@ -26,10 +27,7 @@ import use_case.signup.SignupInputBoundary; import use_case.signup.SignupInteractor; import use_case.signup.SignupOutputBoundary; -import view.LoggedInView; -import view.LoginView; -import view.SignupView; -import view.ViewManager; +import view.*; import javax.swing.*; import java.awt.*; @@ -50,6 +48,8 @@ public class AppBuilder { // DAO version using a shared external database // final DBUserDataAccessObject userDataAccessObject = new DBUserDataAccessObject(userFactory); + private ManageApplicationView manageApplicationView; + private ManageApplicationViewModel manageApplicationViewModel; private SignupView signupView; private SignupViewModel signupViewModel; private LoginViewModel loginViewModel; @@ -61,6 +61,13 @@ public AppBuilder() { cardPanel.setLayout(cardLayout); } + public AppBuilder addManageApplicationView() { + manageApplicationViewModel = new ManageApplicationViewModel(); + manageApplicationView = new ManageApplicationView(manageApplicationViewModel); + cardPanel.add(manageApplicationView, manageApplicationView.getViewName()); + return this; + } + public AppBuilder addSignupView() { signupViewModel = new SignupViewModel(); signupView = new SignupView(signupViewModel); @@ -137,7 +144,6 @@ public JFrame build() { application.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); application.add(cardPanel); - viewManagerModel.setState(signupView.getViewName()); viewManagerModel.firePropertyChange(); diff --git a/src/main/java/app/MainDatabase.java b/src/main/java/app/MainDatabase.java new file mode 100644 index 00000000..17c1d7c9 --- /dev/null +++ b/src/main/java/app/MainDatabase.java @@ -0,0 +1,52 @@ +//Creating this file temporarily to put data in the database. Should be included with Main later on. + +package app; + +import data_access.*; +import java.sql.Connection; + +public class MainDatabase { + public static void main(String[] args) throws Exception { + // Step 1: Connect to SQLite database + Connection conn = DatabaseConnection.connect(); + DatabasePetGateway dbGateway = new DatabasePetGateway(conn); + + // Step 2: Populate DB from API if empty + var existingPets = dbGateway.fetchPets("", ""); + if (existingPets.isEmpty()) { + System.out.println("🐾 Database is empty — importing pets from API..."); + + String[] speciesList = {"dog", "cat", "rabbit", "bird", "horse"}; // Can add more types + int totalImported = 0; + + for (String species : speciesList) { + // Get a new token for every API call (prevents "token expired" errors) + String token = PetfinderAuthService.getAccessToken(); + PetfinderAPIGateway apiGateway = new PetfinderAPIGateway(token); + + System.out.println("Fetching " + species + " from API..."); + var pets = apiGateway.fetchPets(species, ""); + + if (pets.isEmpty()) { + System.out.println("⚠️ No pets fetched for " + species + " — check API or token"); + } else { + for (var pet : pets) { + dbGateway.addPet(pet); + } + totalImported += pets.size(); + System.out.println("Imported " + pets.size() + " " + species + "(s) into database!"); + } + } + + System.out.println("Total pets imported: " + totalImported); + } + + // Step 3: Show how many pets are in the database + var allPets = dbGateway.fetchPets("", ""); + System.out.println("Total pets in database: " + allPets.size()); + for (var pet : allPets) { + System.out.println(pet.getType()); + } + + } +} diff --git a/src/main/java/data_access/ApplicationGatewayInterface.java b/src/main/java/data_access/ApplicationGatewayInterface.java new file mode 100644 index 00000000..c742f865 --- /dev/null +++ b/src/main/java/data_access/ApplicationGatewayInterface.java @@ -0,0 +1,9 @@ +package data_access; + +import entity.Application; + +import java.util.List; + +public interface ApplicationGatewayInterface { +// Application fetchApplicationById(String applicationId); +} diff --git a/src/main/java/data_access/DBApplicationDataAccessObject.java b/src/main/java/data_access/DBApplicationDataAccessObject.java new file mode 100644 index 00000000..2f338f2a --- /dev/null +++ b/src/main/java/data_access/DBApplicationDataAccessObject.java @@ -0,0 +1,5 @@ +package data_access; + +public class DBApplicationDataAccessObject { + +} diff --git a/src/main/java/data_access/DBUserDataAccessObject.java b/src/main/java/data_access/DBUserDataAccessObject.java index 08cc04ad..18209c82 100644 --- a/src/main/java/data_access/DBUserDataAccessObject.java +++ b/src/main/java/data_access/DBUserDataAccessObject.java @@ -9,6 +9,7 @@ import use_case.login.LoginUserDataAccessInterface; import use_case.logout.LogoutUserDataAccessInterface; import use_case.signup.SignupUserDataAccessInterface; +import use_case.submit_application.SubmitUserDataAccessInterface; import java.io.IOException; @@ -18,7 +19,9 @@ public class DBUserDataAccessObject implements SignupUserDataAccessInterface, LoginUserDataAccessInterface, ChangePasswordUserDataAccessInterface, - LogoutUserDataAccessInterface { + LogoutUserDataAccessInterface, + SubmitUserDataAccessInterface { + private static final int SUCCESS_CODE = 200; private static final String CONTENT_TYPE_LABEL = "Content-Type"; private static final String CONTENT_TYPE_JSON = "application/json"; @@ -52,7 +55,7 @@ public User get(String username) { final String name = userJSONObject.getString(USERNAME); final String password = userJSONObject.getString(PASSWORD); - return userFactory.create(name, password); + return userFactory.create("visitor", name, password); } else { throw new RuntimeException(responseBody.getString(MESSAGE)); diff --git a/src/main/java/data_access/DatabaseApplicationGateway.java b/src/main/java/data_access/DatabaseApplicationGateway.java new file mode 100644 index 00000000..1a46049d --- /dev/null +++ b/src/main/java/data_access/DatabaseApplicationGateway.java @@ -0,0 +1,81 @@ +package data_access; + +import entity.Application; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +public class DatabaseApplicationGateway implements ApplicationGatewayInterface { + private final Connection conn; + + public DatabaseApplicationGateway(Connection conn) { + this.conn = conn; + } + +// @Override +// public Application fetchApplicationById(String applicationId) { // why does applicationID have to be a string not int? +// String sql = "SELECT * FROM pets WHERE id = ?"; +// try (PreparedStatement stmt = conn.prepareStatement(sql)) { // here +// stmt.setString(1, applicationId); +// ResultSet rs = stmt.executeQuery(); +// if (rs.next()) { +// return new Application( +//// rs.getString("id"), +//// rs.getString("application_id"), //TODO: make Application entity, pass in personal_info list, not separate fields! +// //List personal_information = getPersonalInformation(user); ..... etc. +//// rs.getString("pet_id"), +//// rs.getString("legal_name"), +//// rs.getString("reason"), +// rs.getString("availability"), +// rs.getString("occupation"), +// rs.getString("age"), +// rs.getString("email"), +// rs.getString("phone"), +// rs.getString("previous_experience") +// ); +// } +// } catch (SQLException e) { +// e.printStackTrace(); +// } +// return null; +// } + + public void addApplication(Application application) { + String sql = "INSERT OR REPLACE INTO applications (id, pet_id, legal_name, reason, availability, " + + "occupation, age, email, phone, previous_experience) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setString(1, application.getApplicationId()); + stmt.setString(2, application.getPetId()); + stmt.setString(3, application.getUser().getFirstName()); + stmt.setString(4, application.getUser().getLastName()); + stmt.setString(5, application.getReason()); + stmt.setString(6, application.getAvailability()); + stmt.setString(7, application.getUser().getOccupation()); + stmt.setString(8, application.getUser().getAge()); + stmt.setString(9, application.getUser().getEmail()); + stmt.setString(10, application.getUser().getPhoneNum()); + stmt.setString(11, application.getPreviousExperience()); + stmt.executeUpdate(); + System.out.println("✅ Added application to DB: " + application.getUser().getLastName() + " " + application.getUser().getLastName() + "'s application for" + + application.getPetId() + "ID: " + application.getApplicationId()); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + public void deleteApplication(String id) { + String sql = "DELETE FROM applications WHERE id = ?"; + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setString(1, id); + stmt.executeUpdate(); + } catch (SQLException e) { + e.printStackTrace(); + } + } +} + + diff --git a/src/main/java/data_access/DatabaseConnection.java b/src/main/java/data_access/DatabaseConnection.java new file mode 100644 index 00000000..7618bf0f --- /dev/null +++ b/src/main/java/data_access/DatabaseConnection.java @@ -0,0 +1,60 @@ +package data_access; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; + +public class DatabaseConnection { + private static final String DB_URL = "jdbc:sqlite:src/main/resources/pets.db"; + + public static Connection connect() throws SQLException { + Connection conn = DriverManager.getConnection(DB_URL); + conn.setAutoCommit(true); // simpler for small projects + createTableIfNotExists(conn); + return conn; + } + + private static void createTableIfNotExists(Connection conn) throws SQLException { + String createTableSQL = """ + CREATE TABLE IF NOT EXISTS pets ( + id TEXT PRIMARY KEY, + name TEXT, + type TEXT, + breed TEXT, + age TEXT, + gender TEXT, + size TEXT, + contact TEXT + ); + """; + try (Statement stmt = conn.createStatement()) { + stmt.execute(createTableSQL); + } + } + + private static void createApplicationTableIfNotExists(Connection conn) throws SQLException { + String createTableSQL = """ + CREATE TABLE IF NOT EXISTS applications ( + id TEXT PRIMARY KEY, + application_id TEXT, + pet_id TEXT, + legal_name TEXT, + reason TEXT, + availability TEXT, + occupation TEXT, + age TEXT, + email TEXT, + phone TEXT, + previous_experience TEXT + ); + """; + try (Statement stmt = conn.createStatement()) { + stmt.execute(createTableSQL); + } + + //pet might not be text, but an id from the pets table so we get the correct one + //might want to find pet id using the pet entity we got from the form + } +} + diff --git a/src/main/java/data_access/DatabasePetGateway.java b/src/main/java/data_access/DatabasePetGateway.java new file mode 100644 index 00000000..47cfb37f --- /dev/null +++ b/src/main/java/data_access/DatabasePetGateway.java @@ -0,0 +1,124 @@ +package data_access; + +import entity.Pet; +import java.sql.*; +import java.util.*; + +public class DatabasePetGateway implements PetAPIGatewayInterface { + + private final Connection conn; + + private final Map petMap = new HashMap<>(); + + public DatabasePetGateway(Connection conn) { + this.conn = conn; + loadAllPetsIntoMap(); + } + + + private void loadAllPetsIntoMap() { + String sql = "SELECT * FROM pets"; + + try (Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(sql)) { + + while (rs.next()) { + Pet pet = new Pet( + rs.getString("id"), + rs.getString("name"), + rs.getString("type"), + rs.getString("breed"), + rs.getString("age"), + rs.getString("gender"), + rs.getString("size"), + rs.getString("contact") + ); + petMap.put(pet.getId(), pet); + } + + System.out.println("📥 Loaded " + petMap.size() + " pets into memory map."); + + } catch (SQLException e) { + e.printStackTrace(); + } + } + + + @Override + public List fetchPets(String type, String gender) { + List pets = new ArrayList<>(); + String sql = "SELECT * FROM pets WHERE type LIKE ? AND gender LIKE ?"; + + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setString(1, type.isEmpty() ? "%" : type); + stmt.setString(2, gender.isEmpty() ? "%" : gender); + ResultSet rs = stmt.executeQuery(); + + while (rs.next()) { + pets.add(new Pet( + rs.getString("id"), + rs.getString("name"), + rs.getString("type"), + rs.getString("breed"), + rs.getString("age"), + rs.getString("gender"), + rs.getString("size"), + rs.getString("contact") + )); + } + + } catch (SQLException e) { + e.printStackTrace(); + } + return pets; + } + + + @Override + public Pet fetchPetById(String petId) { + return petMap.get(petId); // O(1) lookup + } + + + public void addPet(Pet pet) { + String sql = "INSERT OR REPLACE INTO pets (id, name, type, breed, age, gender, size, contact) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; + + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setString(1, pet.getId()); + stmt.setString(2, pet.getName()); + stmt.setString(3, pet.getType()); + stmt.setString(4, pet.getBreed()); + stmt.setString(5, pet.getAge()); + stmt.setString(6, pet.getGender()); + stmt.setString(7, pet.getSize()); + stmt.setString(8, pet.getContact()); + stmt.executeUpdate(); + + // Update map + petMap.put(pet.getId(), pet); + + System.out.println("✅ Added pet to DB + map: " + pet.getName()); + + } catch (SQLException e) { + e.printStackTrace(); + } + } + + + public void removePet(String id) { + String sql = "DELETE FROM pets WHERE id = ?"; + + try (PreparedStatement stmt = conn.prepareStatement(sql)) { + stmt.setString(1, id); + stmt.executeUpdate(); + + // remove from map + petMap.remove(id); + + } catch (SQLException e) { + e.printStackTrace(); + } + } +} + + diff --git a/src/main/java/data_access/FileUserDataAccessObject.java b/src/main/java/data_access/FileUserDataAccessObject.java index 4cae88c5..03503d6a 100644 --- a/src/main/java/data_access/FileUserDataAccessObject.java +++ b/src/main/java/data_access/FileUserDataAccessObject.java @@ -6,6 +6,7 @@ import use_case.login.LoginUserDataAccessInterface; import use_case.logout.LogoutUserDataAccessInterface; import use_case.signup.SignupUserDataAccessInterface; +import use_case.submit_application.SubmitUserDataAccessInterface; import java.io.*; import java.util.HashMap; @@ -18,7 +19,8 @@ public class FileUserDataAccessObject implements SignupUserDataAccessInterface, LoginUserDataAccessInterface, ChangePasswordUserDataAccessInterface, - LogoutUserDataAccessInterface { + LogoutUserDataAccessInterface, + SubmitUserDataAccessInterface { private static final String HEADER = "username,password"; @@ -57,7 +59,7 @@ public FileUserDataAccessObject(String csvPath, UserFactory userFactory) { final String[] col = row.split(","); final String username = String.valueOf(col[headers.get("username")]); final String password = String.valueOf(col[headers.get("password")]); - final User user = userFactory.create(username, password); + final User user = userFactory.create("visitor", username, password); accounts.put(username, user); } } diff --git a/src/main/java/data_access/InMemoryPetDataAccessObject.java b/src/main/java/data_access/InMemoryPetDataAccessObject.java new file mode 100644 index 00000000..fc465d40 --- /dev/null +++ b/src/main/java/data_access/InMemoryPetDataAccessObject.java @@ -0,0 +1,54 @@ +package data_access; + +import entity.Pet; +import use_case.add_pet.AddPetDataAccessInterface; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class InMemoryPetDataAccessObject implements AddPetDataAccessInterface { + private final Map pets = new HashMap<>(); + + + // Optional: expose for debugging/testing + public Collection getAllPets() { + return pets.values(); + } + + @Override + public boolean existsPet(List petData) { + for (Pet pet : pets.values()) { + if (pet.getName().equals(petData.get(0))) { + if(pet.getGender().equals(petData.get(1)) + &&pet.getAge().equals(petData.get(2)) + &&pet.getType().equals(petData.get(3)) + &&pet.getSize().equals(petData.get(4)) + &&pet.getBreed().equals(petData.get(5)) + ){ + return true; + } + return false; + } + } + return false; + }; + + @Override + public void add(Pet pet) { + + } + @Override + public String generateId(String type) { + String prefix = type.toUpperCase().replaceAll("\\s+", ""); + long count = pets.values().stream() + .filter(p -> p.getType().equalsIgnoreCase(type)) + .count(); + + long next = count + 1; + + return prefix + "-" + String.format("%03d", next); + } +} + diff --git a/src/main/java/data_access/InMemoryUserDataAccessObject.java b/src/main/java/data_access/InMemoryUserDataAccessObject.java index fc5dd2b2..e36fd54e 100644 --- a/src/main/java/data_access/InMemoryUserDataAccessObject.java +++ b/src/main/java/data_access/InMemoryUserDataAccessObject.java @@ -5,6 +5,7 @@ import use_case.login.LoginUserDataAccessInterface; import use_case.logout.LogoutUserDataAccessInterface; import use_case.signup.SignupUserDataAccessInterface; +import use_case.submit_application.SubmitUserDataAccessInterface; import java.util.HashMap; import java.util.Map; @@ -16,7 +17,8 @@ public class InMemoryUserDataAccessObject implements SignupUserDataAccessInterface, LoginUserDataAccessInterface, ChangePasswordUserDataAccessInterface, - LogoutUserDataAccessInterface { + LogoutUserDataAccessInterface, + SubmitUserDataAccessInterface { private final Map users = new HashMap<>(); diff --git a/src/main/java/data_access/PetAPIGatewayInterface.java b/src/main/java/data_access/PetAPIGatewayInterface.java new file mode 100644 index 00000000..d5e8cc50 --- /dev/null +++ b/src/main/java/data_access/PetAPIGatewayInterface.java @@ -0,0 +1,9 @@ +package data_access; + +import entity.Pet; +import java.util.List; + +public interface PetAPIGatewayInterface { + List fetchPets(String species, String gender); + Pet fetchPetById(String petId); +} diff --git a/src/main/java/data_access/PetfinderAPIGateway.java b/src/main/java/data_access/PetfinderAPIGateway.java new file mode 100644 index 00000000..b7fd04a4 --- /dev/null +++ b/src/main/java/data_access/PetfinderAPIGateway.java @@ -0,0 +1,72 @@ +package data_access; + +import entity.Pet; +import okhttp3.*; +import org.json.*; + +import java.util.ArrayList; +import java.util.List; + +public class PetfinderAPIGateway implements PetAPIGatewayInterface { + + private final OkHttpClient client = new OkHttpClient(); + private final String apiToken; + + public PetfinderAPIGateway(String apiToken) { + this.apiToken = apiToken; + } + + @Override + public List fetchPets(String type, String gender) { + List pets = new ArrayList<>(); + + HttpUrl.Builder urlBuilder = HttpUrl.parse("https://api.petfinder.com/v2/animals").newBuilder(); + if (!type.isBlank()) urlBuilder.addQueryParameter("type", type); + if (!gender.isBlank()) urlBuilder.addQueryParameter("gender", gender); + urlBuilder.addQueryParameter("limit", "100"); + + Request request = new Request.Builder() + .url(urlBuilder.build()) + .addHeader("Authorization", "Bearer " + apiToken) + .build(); + + try (Response response = client.newCall(request).execute()) { + String jsonString = response.body().string(); + JSONObject root = new JSONObject(jsonString); + + JSONArray animals = root.getJSONArray("animals"); + for (int i = 0; i < animals.length(); i++) { + JSONObject a = animals.getJSONObject(i); + + String id = String.valueOf(a.getInt("id")); + String name = a.optString("name", "Unknown"); + String species = a.optString("species", "Unknown"); + JSONObject breeds = a.getJSONObject("breeds"); + String breed = breeds.optString("primary", "Unknown"); + String age = a.optString("age", "Unknown"); + String g = a.optString("gender", "Unknown"); + String size = a.optString("size", "Unknown"); + + String contact = ""; + if (a.has("contact")) { + JSONObject c = a.getJSONObject("contact"); + contact = c.optString("email", ""); + } + + pets.add(new Pet(id, name, species, breed, age, g, size, contact)); + } + + } catch (Exception e) { + e.printStackTrace(); + } + + return pets; + } + + @Override + public Pet fetchPetById(String petId) { + // Optional for later use + return null; + } +} + diff --git a/src/main/java/data_access/PetfinderAuthService.java b/src/main/java/data_access/PetfinderAuthService.java new file mode 100644 index 00000000..f683b5f5 --- /dev/null +++ b/src/main/java/data_access/PetfinderAuthService.java @@ -0,0 +1,39 @@ +package data_access; + +import okhttp3.*; +import org.json.JSONObject; + +public class PetfinderAuthService { + + private static final String CLIENT_ID = "98LHq0XnAgjCVHKzTakl9iTR7lnOKkOfq9b9JxlyXBhczzXP7z"; + private static final String CLIENT_SECRET = "wOuOnBiPZBpNYyB54epVnhPyZuYuZ6H9XYvsHRuk"; + private static final String TOKEN_URL = "https://api.petfinder.com/v2/oauth2/token"; + + public static String getAccessToken() throws Exception { + OkHttpClient client = new OkHttpClient(); + + RequestBody formBody = new FormBody.Builder() + .add("grant_type", "client_credentials") + .add("client_id", CLIENT_ID) + .add("client_secret", CLIENT_SECRET) + .build(); + + Request request = new Request.Builder() + .url(TOKEN_URL) + .post(formBody) + .build(); + + try (Response response = client.newCall(request).execute()) { + if (!response.isSuccessful()) { + throw new RuntimeException("❌ Failed to get token: " + response.code() + " - " + response.message()); + } + + String responseBody = response.body().string(); + JSONObject json = new JSONObject(responseBody); + String token = json.getString("access_token"); + System.out.println("🔑 Received token: " + token); + return token; + } + } +} + diff --git a/src/main/java/entity/Administrator.java b/src/main/java/entity/Administrator.java new file mode 100644 index 00000000..f32637bb --- /dev/null +++ b/src/main/java/entity/Administrator.java @@ -0,0 +1,14 @@ +package entity; + +public class Administrator extends User{ + /** + * Creates a new user with the given non-empty name and non-empty password. + * + * @param name the username + * @param password the password + * @throws IllegalArgumentException if the password or name are empty + */ + public Administrator(String name, String password) { + super(name, password); + } +} diff --git a/src/main/java/entity/Application.java b/src/main/java/entity/Application.java new file mode 100644 index 00000000..d433cd33 --- /dev/null +++ b/src/main/java/entity/Application.java @@ -0,0 +1,90 @@ + +package entity; +import java.util.ArrayList; +import java.util.List; + +public class Application { + + // Class variable to keep track of how many applcations, used as id + public static int counter = 0; + + // Application ID for internal use + private String application_id; + + // Applicant Information + private Visitor user; + + // Which Pet to adopt by id + private String pet_id; + + // + private String reason_to_adopt; + private String home_environment; // describe, apartment, small, big, etc. + // give hint on how to fill out each field + private String availability; + // explain their availability + private String previous_experience; + private List personal_information; + + // helper method, to gather all info from the user + private List getPersonalInformation(Visitor user) { + // get all personal info from visitor + String first_name = user.getFirstName(); + String last_name = user.getLastName(); + String email = user.getEmail(); + String phone_number = user.getPhoneNum(); + String age = user.getAge(); + String occupation = user.getOccupation(); + + List personal_information = new ArrayList<>(); + personal_information.add(first_name); + personal_information.add(last_name); + personal_information.add(email); + personal_information.add(phone_number); + personal_information.add(age); + personal_information.add(occupation); + + return personal_information; + } + + /** + * Creates a new application + * @throws IllegalArgumentException if the password or name are empty + */ + // + public Application(Visitor user, String pet_id, String reason_to_adopt, String home_environment, String availability, String previous_experience) { + List personal_information = getPersonalInformation(user); + // loop through the list, see if any is empty, if yes throw an error + for (String info : personal_information) { + if ("".equals(info)) { + throw new IllegalArgumentException("This information cannot be empty." + + "Please fill out your personal information in setting."); + } + } + // set all attributes + this.pet_id = pet_id; + this.personal_information = personal_information; + this.reason_to_adopt = reason_to_adopt; + this.home_environment = home_environment; + this.availability = availability; + this.previous_experience = previous_experience; + this.application_id = Integer.toString(counter); // use counter count as id of application + counter++; // increase counter count by 1 + + } + + // Getter methods + public List getPersonalInformation() { + return personal_information; + } + public String getReason() { + return reason_to_adopt; + } + public String getHomeEnvironment() {return home_environment;} + public String getPreviousExperience() {return previous_experience;} + public String getPetId() {return pet_id;} + public String getApplicationId() {return application_id;} + public String getAvailability() {return availability;} + public Visitor getUser() {return user;} + +} diff --git a/src/main/java/entity/Gallery.java b/src/main/java/entity/Gallery.java new file mode 100644 index 00000000..a3f4bff8 --- /dev/null +++ b/src/main/java/entity/Gallery.java @@ -0,0 +1,25 @@ +package entity; + +import java.util.Collections; +import java.util.List; + +public class Gallery { + private final List pets; + + public Gallery(List pets) { + this.pets = pets == null ? Collections.emptyList() : Collections.unmodifiableList(pets); + } + + public List getPets() { + return pets; + } + + public int size() { + return pets.size(); + } + + public boolean isEmpty() { + return pets.isEmpty(); + } +} + diff --git a/src/main/java/entity/Pet.java b/src/main/java/entity/Pet.java new file mode 100644 index 00000000..f66e8517 --- /dev/null +++ b/src/main/java/entity/Pet.java @@ -0,0 +1,41 @@ +package entity; + +public class Pet { + private String id; + private String name; + private String type; + private String breed; + private String age; + private String gender; + private String size; + private String contact; + + public Pet(String id, String name, String type, String breed, + String age, String gender, String size, String contact) { + this.id = id; + this.name = name; + this.type = type; + this.breed = breed; + this.age = age; + this.gender = gender; + this.size = size; + this.contact = contact; + } + + // Getters + public String getId() { return id; } + public String getName() { return name; } + public String getType() { return type; } + public String getBreed() { return breed; } + public String getAge() { return age; } + public String getGender() { return gender; } + public String getSize() { return size; } + public String getContact() { return contact; } + + + @Override + public String toString() { + return name + " (" + type + ", " + breed + ", " + gender + ")"; + } +} + diff --git a/src/main/java/entity/PetFactory.java b/src/main/java/entity/PetFactory.java new file mode 100644 index 00000000..9fc5010e --- /dev/null +++ b/src/main/java/entity/PetFactory.java @@ -0,0 +1,8 @@ +package entity; +//Factory for creating Pet Objects +public class PetFactory { + public Pet create(String id, String name, String type, String breed, String age, String gender, + String size, String contact) { + return new Pet(id, name, type,breed, age ,gender,size,contact); + } +} diff --git a/src/main/java/entity/UserFactory.java b/src/main/java/entity/UserFactory.java index 238578d3..0ce43862 100644 --- a/src/main/java/entity/UserFactory.java +++ b/src/main/java/entity/UserFactory.java @@ -5,7 +5,14 @@ */ public class UserFactory { - public User create(String name, String password) { - return new User(name, password); + public User create(String type, String name, String password) { + switch (type.toLowerCase()) { + case "visitor": + return new Visitor(name, password); + case "administrator": + return new Administrator(name, password); + default: + throw new IllegalArgumentException("Unknown user type: " + type); + } } } diff --git a/src/main/java/entity/Visitor.java b/src/main/java/entity/Visitor.java new file mode 100644 index 00000000..8679a71a --- /dev/null +++ b/src/main/java/entity/Visitor.java @@ -0,0 +1,100 @@ +package entity; + +public class Visitor extends User{ + + private String firstName; + private String lastName; + private String address; + private String homeEvi; + private String occupation; + private String phoneNum; + private String email; + private String age; + private String phoneNumber; + private String email; + + /** + * Creates a new user with the given non-empty name and non-empty password. + * + * @param name the username + * @param password the password + * @throws IllegalArgumentException if the password or name are empty + */ + public Visitor(String name, String password) { + super(name, password); + this.firstName = ""; + this.lastName = ""; + this.address = ""; + this.homeEvi = ""; + this.occupation = ""; + this.email = ""; + this.phoneNum = ""; + this.age = ""; + } + + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public String getAddress() { + return address; + } + + public void setAddress(String address) { + this.address = address; + } + + public String getHomeEvi() { + return homeEvi; + } + + public void setHomeEvi(String homeEvi) { + this.homeEvi = homeEvi; + } + + public String getOccupation() { + return occupation; + } + + public void setOccupation(String occupation) { + this.occupation = occupation; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getAge() { + return age; + } + + public void setAge(String age) { + this.age = age; + } + + public String getPhoneNum() { + return phoneNum; + } + + public void setPhoneNum(String phoneNum) { + this.phoneNum = phoneNum; + } + +} diff --git a/src/main/java/interface_adapter/add_pet/AddPetController.java b/src/main/java/interface_adapter/add_pet/AddPetController.java new file mode 100644 index 00000000..0fc11999 --- /dev/null +++ b/src/main/java/interface_adapter/add_pet/AddPetController.java @@ -0,0 +1,28 @@ +package interface_adapter.add_pet; + +import use_case.add_pet.AddPetInputData; +import use_case.add_pet.AddPetInputBoundary; + +public class AddPetController { + + private final AddPetInputBoundary addPetUsecaseInteractor; + + public AddPetController(AddPetInputBoundary addPetUsecaseInteractor) { + this.addPetUsecaseInteractor = addPetUsecaseInteractor; + } + + public void execute( + String name, + String type, + String breed, + String age, + String gender, + String size, + String contact) { + + AddPetInputData inputData = new AddPetInputData(name, type, breed, age, gender, size, contact); + + addPetUsecaseInteractor.execute(inputData); + } +} + diff --git a/src/main/java/interface_adapter/add_pet/AddPetPresenter.java b/src/main/java/interface_adapter/add_pet/AddPetPresenter.java new file mode 100644 index 00000000..0ed07b33 --- /dev/null +++ b/src/main/java/interface_adapter/add_pet/AddPetPresenter.java @@ -0,0 +1,26 @@ +package interface_adapter.add_pet; + +import use_case.add_pet.AddPetOutputBoundary; +import use_case.add_pet.AddPetOutputData; + +public class AddPetPresenter implements AddPetOutputBoundary { + + private final AddPetViewModel viewModel; + + public AddPetPresenter(AddPetViewModel viewModel) { + this.viewModel = viewModel; + } + + @Override + public void prepareSuccessView(AddPetOutputData data) { + viewModel.setStatusMessage(data.getMessage()); + //viewModel.firePropertyChanged(); + } + + @Override + public void prepareFailView(String errorMessage) { + viewModel.setStatusMessage("Failed to add pet: " + errorMessage); + //viewModel.firePropertyChanged(); + } +} + diff --git a/src/main/java/interface_adapter/add_pet/AddPetView.java b/src/main/java/interface_adapter/add_pet/AddPetView.java new file mode 100644 index 00000000..6f542b13 --- /dev/null +++ b/src/main/java/interface_adapter/add_pet/AddPetView.java @@ -0,0 +1,136 @@ +package interface_adapter.add_pet; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +public class AddPetView extends JPanel implements ActionListener, PropertyChangeListener { + + private final String viewName = "Add Pet"; + + private final JTextField nameInputField = new JTextField(15); + private final JTextField typeInputField = new JTextField(15); + private final JTextField breedInputField = new JTextField(15); + private final JTextField contactInputField = new JTextField(15); + + private final JComboBox ageDropdown = + new JComboBox<>(new String[]{"Baby", "Young", "Adult"}); + + private final JComboBox genderDropdown = + new JComboBox<>(new String[]{"Male", "Female"}); + + private final JComboBox sizeDropdown = + new JComboBox<>(new String[]{"Small", "Medium", "Large"}); + + + private final JButton submitButton = new JButton("Add Pet"); + private final JButton cancelButton = new JButton("Cancel"); + private final JButton clearButton = new JButton("Clear Fields"); + + // The controller for this view + private AddPetController addPetController; + private AddPetViewModel viewModel; + + public AddPetView() { + setLayout(new BorderLayout()); + + JPanel formPanel = new JPanel(); + JPanel buttons = new JPanel(); + formPanel.setLayout(new GridLayout(0, 2, 5, 5)); + + formPanel.add(new JLabel("Pet Name:")); + formPanel.add(nameInputField); + + formPanel.add(new JLabel("Type:")); + formPanel.add(typeInputField); + + formPanel.add(new JLabel("Breed:")); + formPanel.add(breedInputField); + + formPanel.add(new JLabel("Age:")); + formPanel.add(ageDropdown); + + formPanel.add(new JLabel("Gender:")); + formPanel.add(genderDropdown); + + formPanel.add(new JLabel("Size:")); + formPanel.add(sizeDropdown); + + formPanel.add(new JLabel("Contact:")); + formPanel.add(contactInputField); + + submitButton.addActionListener(this); + cancelButton.addActionListener(this); + clearButton.addActionListener(this); + + buttons.add(submitButton); + buttons.add(cancelButton); + + add(formPanel, BorderLayout.CENTER); + add(clearButton, BorderLayout.NORTH); + add(buttons, BorderLayout.SOUTH); + } + + public String getViewName() { + return viewName; + } + + public void setAddPetController(AddPetController controller) { + this.addPetController = controller; + } + + @Override + public void actionPerformed(ActionEvent e) { + Object source = e.getSource(); + + if (source == submitButton) { + // Add Pet + if (addPetController != null) { + addPetController.execute( + nameInputField.getText(), + typeInputField.getText(), + breedInputField.getText(), + ageDropdown.getSelectedItem().toString(), + genderDropdown.getSelectedItem().toString(), + sizeDropdown.getSelectedItem().toString(), + contactInputField.getText() + ); + } + } + + else if (source == cancelButton) { + // Close the parent window + JFrame frame = (JFrame) SwingUtilities.getWindowAncestor(this); + if (frame != null) { + frame.dispose(); + } + } + + else if (source == clearButton) { + // Clear all fields + nameInputField.setText(""); + typeInputField.setText(""); + breedInputField.setText(""); + ageDropdown.setSelectedIndex(0); + genderDropdown.setSelectedIndex(0); + sizeDropdown.setSelectedIndex(0); + contactInputField.setText(""); + } + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + // This is where the presenter can update UI elements. + if (evt.getPropertyName().equals("addPetStatus")) { + JOptionPane.showMessageDialog(this, evt.getNewValue().toString()); + } + } + + public void setViewModel(AddPetViewModel viewModel) { + this.viewModel = viewModel; + this.viewModel.addPropertyChangeListener(this); + } +} diff --git a/src/main/java/interface_adapter/add_pet/AddPetViewModel.java b/src/main/java/interface_adapter/add_pet/AddPetViewModel.java new file mode 100644 index 00000000..338b0f1c --- /dev/null +++ b/src/main/java/interface_adapter/add_pet/AddPetViewModel.java @@ -0,0 +1,20 @@ +package interface_adapter.add_pet; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; + +public class AddPetViewModel { + private final PropertyChangeSupport support = new PropertyChangeSupport(this); + private String statusMessage; + + public void setStatusMessage(String message) { + String old = this.statusMessage; + this.statusMessage = message; + support.firePropertyChange("addPetStatus", old, this.statusMessage); + } + + public void addPropertyChangeListener(PropertyChangeListener l) { + support.addPropertyChangeListener(l); + } +} + diff --git a/src/main/java/interface_adapter/browse_filter/BrowseFilterController.java b/src/main/java/interface_adapter/browse_filter/BrowseFilterController.java new file mode 100644 index 00000000..fd488570 --- /dev/null +++ b/src/main/java/interface_adapter/browse_filter/BrowseFilterController.java @@ -0,0 +1,16 @@ +package interface_adapter.browse_filter; + +import use_case.browse_filter.*; + +public class BrowseFilterController { + private final BrowseFilterInputBoundary interactor; + + public BrowseFilterController(BrowseFilterInputBoundary interactor) { + this.interactor = interactor; + } + + public void execute(String type, String gender) { + BrowseFilterInputData inputData = new BrowseFilterInputData(type, gender); + interactor.execute(inputData); + } +} diff --git a/src/main/java/interface_adapter/browse_filter/BrowseFilterPresenter.java b/src/main/java/interface_adapter/browse_filter/BrowseFilterPresenter.java new file mode 100644 index 00000000..0a1da669 --- /dev/null +++ b/src/main/java/interface_adapter/browse_filter/BrowseFilterPresenter.java @@ -0,0 +1,31 @@ +package interface_adapter.browse_filter; + +import entity.Pet; +import use_case.browse_filter.BrowseFilterOutputBoundary; +import use_case.browse_filter.BrowseFilterOutputData; + +import java.util.List; +import java.util.stream.Collectors; + +public class BrowseFilterPresenter implements BrowseFilterOutputBoundary { + + private final BrowseFilterViewModel viewModel; + + public BrowseFilterPresenter(BrowseFilterViewModel vm) { + this.viewModel = vm; + } + + @Override + public void present(BrowseFilterOutputData outputData) { + List petStrings = outputData.getPets().stream() + .map(p -> p.getName() + " | " + p.getType() + " | " + p.getBreed() + " | " + p.getGender()) + .collect(Collectors.toList()); + + // ★ Access the state inside the ViewModel + BrowseFilterState state = viewModel.getState(); + state.setPets(petStrings); + + // ★ Notify the view that P E T S changed + viewModel.firePropertyChange("pets"); + } +} diff --git a/src/main/java/interface_adapter/browse_filter/BrowseFilterState.java b/src/main/java/interface_adapter/browse_filter/BrowseFilterState.java new file mode 100644 index 00000000..006e1474 --- /dev/null +++ b/src/main/java/interface_adapter/browse_filter/BrowseFilterState.java @@ -0,0 +1,60 @@ +package interface_adapter.browse_filter; + +import java.util.ArrayList; +import java.util.List; + +/** + * The state for the Browse/Filter View Model. + */ +public class BrowseFilterState { + + private String selectedSpecies = ""; + private String selectedGender = ""; + private String speciesError = ""; + private String genderError = ""; + + // The list of pets the UI should display + private List pets = new ArrayList<>(); + + // --- Getters --- + public String getSelectedSpecies() { + return selectedSpecies; + } + + public String getSelectedGender() { + return selectedGender; + } + + public String getSpeciesError() { + return speciesError; + } + + public String getGenderError() { + return genderError; + } + + public List getPets() { + return pets; + } + + // --- Setters --- + public void setSelectedSpecies(String selectedSpecies) { + this.selectedSpecies = selectedSpecies; + } + + public void setSelectedGender(String selectedGender) { + this.selectedGender = selectedGender; + } + + public void setSpeciesError(String speciesError) { + this.speciesError = speciesError; + } + + public void setGenderError(String genderError) { + this.genderError = genderError; + } + + public void setPets(List pets) { + this.pets = pets; + } +} diff --git a/src/main/java/interface_adapter/browse_filter/BrowseFilterViewModel.java b/src/main/java/interface_adapter/browse_filter/BrowseFilterViewModel.java new file mode 100644 index 00000000..476edf9b --- /dev/null +++ b/src/main/java/interface_adapter/browse_filter/BrowseFilterViewModel.java @@ -0,0 +1,17 @@ +package interface_adapter.browse_filter; + +import interface_adapter.ViewModel; + +public class BrowseFilterViewModel extends ViewModel { + + public static final String TITLE_LABEL = "Browse Pets"; + public static final String SPECIES_LABEL = "Species"; + public static final String GENDER_LABEL = "Gender"; + public static final String APPLY_FILTERS_BUTTON_LABEL = "Apply Filters"; + + public BrowseFilterViewModel() { + super("browse filter"); + setState(new BrowseFilterState()); + } +} + diff --git a/src/main/java/interface_adapter/logout/LogoutController.java b/src/main/java/interface_adapter/logout/LogoutController.java index 49eedf89..6b915717 100644 --- a/src/main/java/interface_adapter/logout/LogoutController.java +++ b/src/main/java/interface_adapter/logout/LogoutController.java @@ -7,16 +7,16 @@ */ public class LogoutController { - private LogoutInputBoundary logoutUseCaseInteractor; + private final LogoutInputBoundary logoutUseCaseInteractor; public LogoutController(LogoutInputBoundary logoutUseCaseInteractor) { - // TODO: Save the interactor in the instance variable. + this.logoutUseCaseInteractor = logoutUseCaseInteractor; } /** * Executes the Logout Use Case. */ public void execute() { - // TODO: run the use case interactor for the logout use case + logoutUseCaseInteractor.execute(); } } diff --git a/src/main/java/interface_adapter/logout/LogoutPresenter.java b/src/main/java/interface_adapter/logout/LogoutPresenter.java index 4df31e73..f2a4d67b 100644 --- a/src/main/java/interface_adapter/logout/LogoutPresenter.java +++ b/src/main/java/interface_adapter/logout/LogoutPresenter.java @@ -1,7 +1,9 @@ package interface_adapter.logout; import interface_adapter.ViewManagerModel; +import interface_adapter.logged_in.LoggedInState; import interface_adapter.logged_in.LoggedInViewModel; +import interface_adapter.login.LoginState; import interface_adapter.login.LoginViewModel; import use_case.logout.LogoutOutputBoundary; import use_case.logout.LogoutOutputData; @@ -11,14 +13,16 @@ */ public class LogoutPresenter implements LogoutOutputBoundary { - private LoggedInViewModel loggedInViewModel; - private ViewManagerModel viewManagerModel; - private LoginViewModel loginViewModel; + private final LoggedInViewModel loggedInViewModel; + private final ViewManagerModel viewManagerModel; + private final LoginViewModel loginViewModel; public LogoutPresenter(ViewManagerModel viewManagerModel, LoggedInViewModel loggedInViewModel, LoginViewModel loginViewModel) { - // TODO: assign to the three instance variables. + this.loggedInViewModel = loggedInViewModel; + this.viewManagerModel = viewManagerModel; + this.loginViewModel = loginViewModel; } @Override @@ -29,12 +33,17 @@ public void prepareSuccessView(LogoutOutputData response) { // We also need to set the username in the LoggedInState to // the empty string. - // TODO: have prepareSuccessView update the LoggedInState + final LoggedInState loggedInState = loggedInViewModel.getState(); + loggedInState.setUsername(""); + this.loggedInViewModel.firePropertyChange(); // 1. get the LoggedInState out of the appropriate View Model, // 2. set the username in the state to the empty string // 3. firePropertyChanged so that the View that is listening is updated. - // TODO: have prepareSuccessView update the LoginState + final LoginState loginState = loginViewModel.getState(); + loginState.setUsername(""); + loginState.setPassword(""); + loginViewModel.firePropertyChange(); // 1. get the LoginState out of the appropriate View Model, // 2. set the username in the state to be the username of the user that just logged out, // 3. firePropertyChanged so that the View that is listening is updated. diff --git a/src/main/java/interface_adapter/manage_application/ManageApplicationApplicationPresenter.java b/src/main/java/interface_adapter/manage_application/ManageApplicationApplicationPresenter.java new file mode 100644 index 00000000..79c17f53 --- /dev/null +++ b/src/main/java/interface_adapter/manage_application/ManageApplicationApplicationPresenter.java @@ -0,0 +1,23 @@ +package interface_adapter.manage_application; + +import interface_adapter.ViewManagerModel; +import interface_adapter.logged_in.LoggedInViewModel; +import interface_adapter.login.LoginViewModel; +import use_case.manage_application.ManageApplicationOutputBoundary; + +public class ManageApplicationApplicationPresenter implements ManageApplicationOutputBoundary { + + + private final ManageApplicationViewModel manageApplicationViewModel; + private final ViewManagerModel viewManagerModel; + + public ManageApplicationApplicationPresenter() { + + } + + @Override + public void prepareSuccessView(ManageApplicationViewModel manageApplicationViewModel) { + + + +} \ No newline at end of file diff --git a/src/main/java/interface_adapter/manage_application/ManageApplicationCardState.java b/src/main/java/interface_adapter/manage_application/ManageApplicationCardState.java new file mode 100644 index 00000000..a79c8ec6 --- /dev/null +++ b/src/main/java/interface_adapter/manage_application/ManageApplicationCardState.java @@ -0,0 +1,31 @@ +package interface_adapter.manage_application; + +/** + * Represents the UI data for a single application card. + */ +public class ManageApplicationCardState { + + private final String applicationId; + private final String title; + private final String status; + private final String subtitle; + + public ManageApplicationCardState(String applicationId, + String title, + String status, + String subtitle) { + + this.applicationId = applicationId; + this.title = title; + this.status = status; + this.subtitle = subtitle; + } + + public String getApplicationId() { return applicationId; } + + public String getTitle() { return title; } + + public String getStatus() { return status; } + + public String getSubtitle() { return subtitle; } +} diff --git a/src/main/java/interface_adapter/manage_application/ManageApplicationController.java b/src/main/java/interface_adapter/manage_application/ManageApplicationController.java new file mode 100644 index 00000000..eb2acb13 --- /dev/null +++ b/src/main/java/interface_adapter/manage_application/ManageApplicationController.java @@ -0,0 +1,4 @@ +package interface_adapter.manage_application; + +public class ManageApplicationController { +} diff --git a/src/main/java/interface_adapter/manage_application/ManageApplicationPresenter.java b/src/main/java/interface_adapter/manage_application/ManageApplicationPresenter.java new file mode 100644 index 00000000..c767d489 --- /dev/null +++ b/src/main/java/interface_adapter/manage_application/ManageApplicationPresenter.java @@ -0,0 +1,50 @@ +//package interface_adapter.manage_application; +// +//import interface_adapter.ViewManagerModel; +//import use_case.manage_application.ManageApplicationOutputBoundary; +// +//public class ManageApplicationPresenter implements ManageApplicationOutputBoundary { +// +// +// private final ManageApplicationViewModel manageApplicationViewModel; +// private final ViewManagerModel viewManagerModel; +// +// public ManageApplicationPresenter() { +// +// } +// +// @Override +// public void prepareSuccessView(ManageApplicationViewModel manageApplicationViewModel) { +// +// +// +//} +package interface_adapter.manage_application; + +import use_case.manage_application.ManageApplicationOutputBoundary; +import use_case.manage_application.ManageApplicationOutputData; + +import java.util.ArrayList; +import java.util.List; + +public class ManageApplicationPresenter implements ManageApplicationOutputBoundary { + + private final ManageApplicationViewModel viewModel; + + public ManageApplicationPresenter(ManageApplicationViewModel viewModel) { + this.viewModel = viewModel; + } + + @Override + public void presentApplications(ManageApplicationOutputData outputData) { + + List cardStates = new ArrayList<>(); + + for (ManageApplicationOutputData.ApplicationData d : outputData.getApps()) { + cardStates.add(new ManageApplicationCardState(d.id, d.title, d.status, d.subtitle)); + } + + ManageApplicationState state = new ManageApplicationState(); + viewModel.setState(state); + } +} diff --git a/src/main/java/interface_adapter/manage_application/ManageApplicationState.java b/src/main/java/interface_adapter/manage_application/ManageApplicationState.java new file mode 100644 index 00000000..0f73cf9f --- /dev/null +++ b/src/main/java/interface_adapter/manage_application/ManageApplicationState.java @@ -0,0 +1,17 @@ +package interface_adapter.manage_application; + +import java.util.ArrayList; +import java.util.List; + +public class ManageApplicationState { + + private final List cards = new ArrayList<>(); + + public List getCards() { + return cards; + } + + public void addCard(ManageApplicationCardState card) { + cards.add(card); + } +} diff --git a/src/main/java/interface_adapter/manage_application/ManageApplicationViewModel.java b/src/main/java/interface_adapter/manage_application/ManageApplicationViewModel.java new file mode 100644 index 00000000..edd77a85 --- /dev/null +++ b/src/main/java/interface_adapter/manage_application/ManageApplicationViewModel.java @@ -0,0 +1,23 @@ +package interface_adapter.manage_application; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; + +public class ManageApplicationViewModel { + + private final PropertyChangeSupport support = new PropertyChangeSupport(this); + + private ManageApplicationState state = new ManageApplicationState(); + + public ManageApplicationState getState() { return state; } + + public void setState(ManageApplicationState newState) { + ManageApplicationState old = this.state; + this.state = newState; + support.firePropertyChange("state", old, newState); + } + + public void addPropertyChangeListener(PropertyChangeListener l) { + support.addPropertyChangeListener(l); + } +} diff --git a/src/main/java/interface_adapter/signup/SignupController.java b/src/main/java/interface_adapter/signup/SignupController.java index c01d25aa..7f2e0a26 100644 --- a/src/main/java/interface_adapter/signup/SignupController.java +++ b/src/main/java/interface_adapter/signup/SignupController.java @@ -5,6 +5,7 @@ /** * Controller for the Signup Use Case. + * Register Their name(First Name and Last Name) and Username and Password */ public class SignupController { @@ -16,13 +17,14 @@ public SignupController(SignupInputBoundary userSignupUseCaseInteractor) { /** * Executes the Signup Use Case. + * @param firstname the First Name + * @param lastname the Last Name * @param username the username to sign up * @param password1 the password * @param password2 the password repeated */ - public void execute(String username, String password1, String password2) { - final SignupInputData signupInputData = new SignupInputData( - username, password1, password2); + public void execute(String firstname, String lastname, String username, String password1, String password2) { + final SignupInputData signupInputData = new SignupInputData(firstname, lastname, username, password1, password2); userSignupUseCaseInteractor.execute(signupInputData); } diff --git a/src/main/java/interface_adapter/signup/SignupState.java b/src/main/java/interface_adapter/signup/SignupState.java index 4a7f6932..75a6d086 100644 --- a/src/main/java/interface_adapter/signup/SignupState.java +++ b/src/main/java/interface_adapter/signup/SignupState.java @@ -4,12 +4,26 @@ * The state for the Signup View Model. */ public class SignupState { + private String firstname = ""; + private String firstnameError = ""; + private String lastname = ""; + private String lastnameError = ""; private String username = ""; - private String usernameError; + private String usernameError = ""; private String password = ""; - private String passwordError; + private String passwordError = ""; private String repeatPassword = ""; - private String repeatPasswordError; + private String repeatPasswordError = ""; + + // --- Getters --- + public String getFirstname() { + return firstname; + } + public String getFirstnameError() {return firstnameError;} + + public String getLastname() {return lastname;} + + public String getLastnameError() {return lastnameError;} public String getUsername() { return username; @@ -35,6 +49,16 @@ public String getRepeatPasswordError() { return repeatPasswordError; } + // --- Setters --- + + public void setFirstname(String firstname) {this.firstname = firstname;} + + public void setFirstnameError(String firstnameError) {this.firstnameError = firstnameError;} + + public void setLastname(String lastname) {this.lastname = lastname;} + + public void setLastnameError(String lastnameError) {this.lastnameError = lastnameError;} + public void setUsername(String username) { this.username = username; } @@ -62,7 +86,9 @@ public void setRepeatPasswordError(String repeatPasswordError) { @Override public String toString() { return "SignupState{" - + "username='" + username + '\'' + + "firstname='" + firstname + '\'' + + ", lastname='" + lastname + '\'' + + ", username='" + username + '\'' + ", password='" + password + '\'' + ", repeatPassword='" + repeatPassword + '\'' + '}'; diff --git a/src/main/java/interface_adapter/signup/SignupViewModel.java b/src/main/java/interface_adapter/signup/SignupViewModel.java index 01f0086b..458aefa8 100644 --- a/src/main/java/interface_adapter/signup/SignupViewModel.java +++ b/src/main/java/interface_adapter/signup/SignupViewModel.java @@ -8,6 +8,8 @@ public class SignupViewModel extends ViewModel { public static final String TITLE_LABEL = "Sign Up View"; + public static final String FIRSTNAME_LABEL = "First Name"; + public static final String LASTNAME_LABEL = "Last Name"; public static final String USERNAME_LABEL = "Choose username"; public static final String PASSWORD_LABEL = "Choose password"; public static final String REPEAT_PASSWORD_LABEL = "Enter password again"; diff --git a/src/main/java/interface_adapter/submit_application/SubmitController.java b/src/main/java/interface_adapter/submit_application/SubmitController.java new file mode 100644 index 00000000..a5c4201c --- /dev/null +++ b/src/main/java/interface_adapter/submit_application/SubmitController.java @@ -0,0 +1,27 @@ +package interface_adapter.submit_application; + +import use_case.submit_application.SubmitInputBoundary; +import use_case.submit_application.SubmitInputData; + +public class SubmitController { + private final SubmitInputBoundary submitUseCaseInteractor; + + + public SubmitController(SubmitInputBoundary submitUseCaseInteractor) { + this.submitUseCaseInteractor = submitUseCaseInteractor; + } + + public void execute(String petId, String username, String firstname, String lastname, String age, String occupation, + String address, String homeEvi, String tel, String email, String reason, + String prevExp, String availability) { + final SubmitInputData submitInputData = new SubmitInputData(petId, username, firstname, lastname, age, occupation, + address, homeEvi, tel, email, reason, prevExp, availability); + + submitUseCaseInteractor.execute(submitInputData); + + } + + public void switchToBrowserFilterView() { + submitUseCaseInteractor.switchToBrowserFilterView(); + } +} diff --git a/src/main/java/interface_adapter/submit_application/SubmitPresenter.java b/src/main/java/interface_adapter/submit_application/SubmitPresenter.java new file mode 100644 index 00000000..8566f569 --- /dev/null +++ b/src/main/java/interface_adapter/submit_application/SubmitPresenter.java @@ -0,0 +1,44 @@ +package interface_adapter.submit_application; + +import interface_adapter.ViewManagerModel; +import use_case.submit_application.SubmitOutputBoundary; + +public class SubmitPresenter implements SubmitOutputBoundary { + private final SubmitViewModel submitViewModel; + private final BrowseFilterViewModel browseFilterViewModel; + private final ViewManagerModel viewManagerModel; + + public SubmitPresenter(ViewManagerModel viewManagerModel, + SubmitViewModel submitViewModel, + BrowseFilterViewModel browseFilterViewModel) { + this.viewManagerModel = viewManagerModel; + this.submitViewModel = submitViewModel; + this.browseFilterViewModel = browseFilterViewModel; + } + + @Override + public void prepareSuccessView(String successMessage) { + //show "submit successfully" to user + final SubmitState submitState = submitViewModel.getState(); + submitState.setSuccess(successMessage); + submitViewModel.firePropertyChange(); + //On success, switch back to BrowserFilter view + viewManagerModel.setState(BrowseFilterViewModel.getViewName()); + viewManagerModel.firePropertyChange(); + } + + @Override + public void prepareFailView(String errorMessage) { + //username error or info not completed + final SubmitState submitState = submitViewModel.getState(); + submitState.setError(errorMessage); + submitViewModel.firePropertyChange(); + } + + @Override + public void switchToBrowserFilterView() { + //for the cancel button + viewManagerModel.setState(BrowseFilterViewModel.getViewName()); + viewManagerModel.firePropertyChange(); + } +} diff --git a/src/main/java/interface_adapter/submit_application/SubmitState.java b/src/main/java/interface_adapter/submit_application/SubmitState.java new file mode 100644 index 00000000..88cf6229 --- /dev/null +++ b/src/main/java/interface_adapter/submit_application/SubmitState.java @@ -0,0 +1,129 @@ +package interface_adapter.submit_application; + +public class SubmitState { + + private String petId = ""; + private String username = ""; + private String firstname = ""; + private String lastname = ""; + private String address = ""; + private String homeEvi = ""; + private String occupation = ""; + private String tel = ""; + private String email = ""; + private String age = ""; + private String reason = ""; + private String prevExp = ""; + private String availability = ""; + private String error = ""; + private String success = ""; + + + public String getPetId() { + return petId; + } + + public void setPetId(String petId) { + this.petId = petId; + } + + public String getUsername() { + return username; + } + public void setUsername(String username) { + this.username = username; + } + + public String getFirstname() { + return firstname; + } + public void setFirstname(String firstname) { + this.firstname = firstname; + } + + public String getLastname() { + return lastname; + } + public void setLastname(String lastname) { + this.lastname = lastname; + } + + public String getAddress() { + return address; + } + public void setAddress(String address) { + this.address = address; + } + + public String getHomeEvi() { + return homeEvi; + } + public void setHomeEvi(String homeEvi) { + this.homeEvi = homeEvi; + } + + public String getOccupation() { + return occupation; + } + public void setOccupation(String occupation) { + this.occupation = occupation; + } + + public String getTel() { + return tel; + } + public void setTel(String tel) { + this.tel = tel; + } + + public String getEmail() { + return email; + } + public void setEmail(String email) { + this.email = email; + } + + public String getAge() { + return age; + } + public void setAge(String age) { + this.age = age; + } + + public String getReason() { + return reason; + } + public void setReason(String reason) { + this.reason = reason; + } + + public String getPrevExp() { + return prevExp; + } + public void setPrevExp(String prevExp) { + this.prevExp = prevExp; + } + + public String getAvailability() { + return availability; + } + public void setAvailability(String availability) { + this.availability = availability; + } + + public String getError() { + return error; + } + + public void setError(String error) { + this.error = error; + } + + public String getSuccess() { + return success; + } + + public void setSuccess(String success) { + this.success = success; + } +} diff --git a/src/main/java/interface_adapter/submit_application/SubmitViewModel.java b/src/main/java/interface_adapter/submit_application/SubmitViewModel.java new file mode 100644 index 00000000..bf4be7fc --- /dev/null +++ b/src/main/java/interface_adapter/submit_application/SubmitViewModel.java @@ -0,0 +1,30 @@ +package interface_adapter.submit_application; + +import interface_adapter.ViewModel; + +public class SubmitViewModel extends ViewModel { + + public static final String TITLE_LABEL = "Start Your Application"; + public static final String USERNAME_LABEL = "Username"; + public static final String FIRSTNAME_LABEL = "First Name"; + public static final String LASTNAME_LABEL = "Last Name"; + public static final String AGE_LABEL = "Enter your age"; + public static final String OCCUPATION_LABEL = "Enter your occupation"; + public static final String ADDRESS_LABEL = "Enter your address"; + public static final String HOME_LABEL = "Describe your home environment"; + public static final String REASON_LABEL = "Reason(s) for wanting to adopt a pet"; + public static final String EXP_LABEL = "Describe your previous experience keeping a pet or pets; " + + "if none, write None."; + public static final String AVAILABILITY_LABEL = "How much time can you spend with the pet?"; + public static final String EMAIL_LABEL = "Enter your email"; + public static final String TEL_LABEL = "Enter your phone number"; + + public static final String SUBMIT_BUTTON_LABEL = "Submit"; + public static final String CANCEL_BUTTON_LABEL = "Cancel"; + + public SubmitViewModel() { + super("submit"); + setState(new SubmitState()); + } + +} diff --git a/src/main/java/resources/pets.db b/src/main/java/resources/pets.db new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/src/main/java/resources/pets.db @@ -0,0 +1 @@ + diff --git a/src/main/java/use_case/add_pet/AddPetDataAccessInterface.java b/src/main/java/use_case/add_pet/AddPetDataAccessInterface.java new file mode 100644 index 00000000..65772fd7 --- /dev/null +++ b/src/main/java/use_case/add_pet/AddPetDataAccessInterface.java @@ -0,0 +1,19 @@ +package use_case.add_pet; + +import entity.Pet; + +import java.util.List; + +public interface AddPetDataAccessInterface { + /** + * Returns true if a pet with this name already exists. + */ + boolean existsPet(List petData); + + /** + * Saves a new pet to the data store. + */ + void add(Pet pet); + + String generateId(String type); +} diff --git a/src/main/java/use_case/add_pet/AddPetInputBoundary.java b/src/main/java/use_case/add_pet/AddPetInputBoundary.java new file mode 100644 index 00000000..983d8766 --- /dev/null +++ b/src/main/java/use_case/add_pet/AddPetInputBoundary.java @@ -0,0 +1,7 @@ +package use_case.add_pet; + +public interface AddPetInputBoundary { + + //Executes the Add Pet Use Case + void execute(AddPetInputData addPetInputData); +} diff --git a/src/main/java/use_case/add_pet/AddPetInputData.java b/src/main/java/use_case/add_pet/AddPetInputData.java new file mode 100644 index 00000000..5c52f649 --- /dev/null +++ b/src/main/java/use_case/add_pet/AddPetInputData.java @@ -0,0 +1,32 @@ +package use_case.add_pet; + +public class AddPetInputData { + private String name; + private String type; + private String breed; + private String age; + private String gender; + private String size; + private String contact; + + public AddPetInputData(String name, String type, String breed, String age, String gender, String size, + String contact) { + + this.name = name; + this.type = type; + this.breed = breed; + this.age = age; + this.gender = gender; + this.size = size; + this.contact = contact; + } + + public String getName() {return name;} + public String getType() {return type;} + public String getBreed() {return breed;} + public String getAge() {return age;} + public String getGender() {return gender;} + public String getSize() {return size;} + public String getContact() {return contact;} + +} diff --git a/src/main/java/use_case/add_pet/AddPetInteractor.java b/src/main/java/use_case/add_pet/AddPetInteractor.java new file mode 100644 index 00000000..13f3d9b3 --- /dev/null +++ b/src/main/java/use_case/add_pet/AddPetInteractor.java @@ -0,0 +1,77 @@ +package use_case.add_pet; + +import entity.Pet; +import entity.PetFactory; + +import java.util.ArrayList; +import java.util.List; + +public class AddPetInteractor implements AddPetInputBoundary { + + private final PetFactory petFactory; + private final AddPetDataAccessInterface petRepo; + private final AddPetOutputBoundary presenter; + + + public AddPetInteractor(PetFactory petFactory, + AddPetDataAccessInterface petRepo, + AddPetOutputBoundary presenter) { + this.petFactory = petFactory; + this.petRepo = petRepo; + this.presenter = presenter; + } + + @Override + public void execute(AddPetInputData inputData) { + + String generatedId = petRepo.generateId(inputData.getType());; + List petData = new ArrayList<>(); + + petData.add(inputData.getName()); + petData.add(inputData.getGender()); + petData.add(inputData.getAge()); + petData.add(inputData.getType()); + petData.add(inputData.getSize()); + petData.add(inputData.getBreed()); + + // -------- CHECK EMPTY FIELDS ---------- + if ( inputData.getName().isEmpty() || + inputData.getType().isEmpty() || + inputData.getBreed().isEmpty() || + inputData.getAge().isEmpty() || + inputData.getGender().isEmpty() || + inputData.getSize().isEmpty() || + inputData.getContact().isEmpty()) { + + presenter.prepareFailView("All fields must be filled out."); + return; + } + + // -------- CHECK DUPLICATE PET ID ---------- + if (petRepo.existsPet(petData)){ + presenter.prepareFailView("A pet already exists."); + return; + } + + // -------- CREATE PET -------- + Pet pet = petFactory.create( + generatedId, + inputData.getName(), + inputData.getType(), + inputData.getBreed(), + inputData.getAge(), + inputData.getGender(), + inputData.getSize(), + inputData.getContact() + ); + + petRepo.add(pet); + //might change to save later + + presenter.prepareSuccessView(new AddPetOutputData("Pet added successfully!", true)); + } +} + + + + diff --git a/src/main/java/use_case/add_pet/AddPetOutputBoundary.java b/src/main/java/use_case/add_pet/AddPetOutputBoundary.java new file mode 100644 index 00000000..6f78230a --- /dev/null +++ b/src/main/java/use_case/add_pet/AddPetOutputBoundary.java @@ -0,0 +1,8 @@ +package use_case.add_pet; + +public interface AddPetOutputBoundary { + void prepareSuccessView(AddPetOutputData outputData); + + void prepareFailView(String errorMessage); + +} diff --git a/src/main/java/use_case/add_pet/AddPetOutputData.java b/src/main/java/use_case/add_pet/AddPetOutputData.java new file mode 100644 index 00000000..a24d863a --- /dev/null +++ b/src/main/java/use_case/add_pet/AddPetOutputData.java @@ -0,0 +1,21 @@ +package use_case.add_pet; + +public class AddPetOutputData { + private final String message; + private final boolean success; + + public AddPetOutputData(String message, boolean success) { + this.message = message; + this.success = success; + } + + public String getMessage() { + return message; + } + + public boolean isSuccess() { + return success; + } +} + + diff --git a/src/main/java/use_case/browse_filter/BrowseFilterInputBoundary.java b/src/main/java/use_case/browse_filter/BrowseFilterInputBoundary.java new file mode 100644 index 00000000..ea805133 --- /dev/null +++ b/src/main/java/use_case/browse_filter/BrowseFilterInputBoundary.java @@ -0,0 +1,5 @@ +package use_case.browse_filter; + +public interface BrowseFilterInputBoundary { + void execute(BrowseFilterInputData inputData); +} diff --git a/src/main/java/use_case/browse_filter/BrowseFilterInputData.java b/src/main/java/use_case/browse_filter/BrowseFilterInputData.java new file mode 100644 index 00000000..14bedcfa --- /dev/null +++ b/src/main/java/use_case/browse_filter/BrowseFilterInputData.java @@ -0,0 +1,19 @@ +package use_case.browse_filter; + +public class BrowseFilterInputData { + private final String type; + private final String gender; + + public BrowseFilterInputData(String type, String gender) { + this.type = type; + this.gender = gender; + } + + public String getType() { + return type; + } + + public String getGender() { + return gender; + } +} diff --git a/src/main/java/use_case/browse_filter/BrowseFilterInteractor.java b/src/main/java/use_case/browse_filter/BrowseFilterInteractor.java new file mode 100644 index 00000000..8835df7a --- /dev/null +++ b/src/main/java/use_case/browse_filter/BrowseFilterInteractor.java @@ -0,0 +1,22 @@ +package use_case.browse_filter; + +import data_access.PetAPIGatewayInterface; +import entity.Pet; +import java.util.List; + +public class BrowseFilterInteractor implements BrowseFilterInputBoundary { + private final PetAPIGatewayInterface petGateway; + private final BrowseFilterOutputBoundary presenter; + + public BrowseFilterInteractor(PetAPIGatewayInterface petGateway, BrowseFilterOutputBoundary presenter) { + this.petGateway = petGateway; + this.presenter = presenter; + } + + @Override + public void execute(BrowseFilterInputData inputData) { + List pets = petGateway.fetchPets(inputData.getType(), inputData.getGender()); + BrowseFilterOutputData outputData = new BrowseFilterOutputData(pets); + presenter.present(outputData); + } +} diff --git a/src/main/java/use_case/browse_filter/BrowseFilterOutputBoundary.java b/src/main/java/use_case/browse_filter/BrowseFilterOutputBoundary.java new file mode 100644 index 00000000..88a43f36 --- /dev/null +++ b/src/main/java/use_case/browse_filter/BrowseFilterOutputBoundary.java @@ -0,0 +1,5 @@ +package use_case.browse_filter; + +public interface BrowseFilterOutputBoundary { + void present(BrowseFilterOutputData outputData); +} diff --git a/src/main/java/use_case/browse_filter/BrowseFilterOutputData.java b/src/main/java/use_case/browse_filter/BrowseFilterOutputData.java new file mode 100644 index 00000000..28627fae --- /dev/null +++ b/src/main/java/use_case/browse_filter/BrowseFilterOutputData.java @@ -0,0 +1,16 @@ +package use_case.browse_filter; + +import entity.Pet; +import java.util.List; + +public class BrowseFilterOutputData { + private final List pets; + + public BrowseFilterOutputData(List pets) { + this.pets = pets; + } + + public List getPets() { + return pets; + } +} diff --git a/src/main/java/use_case/change_password/ChangePasswordInteractor.java b/src/main/java/use_case/change_password/ChangePasswordInteractor.java index 8fe1f0e4..12a0f1a1 100644 --- a/src/main/java/use_case/change_password/ChangePasswordInteractor.java +++ b/src/main/java/use_case/change_password/ChangePasswordInteractor.java @@ -25,7 +25,7 @@ public void execute(ChangePasswordInputData changePasswordInputData) { userPresenter.prepareFailView("New password cannot be empty"); } else { - final User user = userFactory.create(changePasswordInputData.getUsername(), + final User user = userFactory.create("visitor", changePasswordInputData.getUsername(), changePasswordInputData.getPassword()); userDataAccessObject.changePassword(user); diff --git a/src/main/java/use_case/login/LoginInputBoundary.java b/src/main/java/use_case/login/AddPetInputBoundary.java similarity index 86% rename from src/main/java/use_case/login/LoginInputBoundary.java rename to src/main/java/use_case/login/AddPetInputBoundary.java index faf72dc9..d174d9d3 100644 --- a/src/main/java/use_case/login/LoginInputBoundary.java +++ b/src/main/java/use_case/login/AddPetInputBoundary.java @@ -3,7 +3,7 @@ /** * Input Boundary for actions which are related to logging in. */ -public interface LoginInputBoundary { +public interface AddPetInputBoundary { /** * Executes the login use case. diff --git a/src/main/java/use_case/logout/LogoutInteractor.java b/src/main/java/use_case/logout/LogoutInteractor.java index d252f7c4..11aa8a6a 100644 --- a/src/main/java/use_case/logout/LogoutInteractor.java +++ b/src/main/java/use_case/logout/LogoutInteractor.java @@ -4,17 +4,22 @@ * The Logout Interactor. */ public class LogoutInteractor implements LogoutInputBoundary { - private LogoutUserDataAccessInterface userDataAccessObject; - private LogoutOutputBoundary logoutPresenter; + private final LogoutUserDataAccessInterface userDataAccessObject; + private final LogoutOutputBoundary logoutPresenter; public LogoutInteractor(LogoutUserDataAccessInterface userDataAccessInterface, LogoutOutputBoundary logoutOutputBoundary) { - // TODO: save the DAO and Presenter in the instance variables. + this.userDataAccessObject = userDataAccessInterface; + this.logoutPresenter = logoutOutputBoundary; } @Override public void execute() { - // TODO: implement the logic of the Logout Use Case + String currentUsername = userDataAccessObject.getCurrentUsername(); + userDataAccessObject.setCurrentUsername(null); + + final LogoutOutputData logoutOutputData = new LogoutOutputData(currentUsername); + logoutPresenter.prepareSuccessView(logoutOutputData); // * set the current username to null in the DAO // * instantiate the `LogoutOutputData`, which needs to contain the username. // * tell the presenter to prepare a success view. diff --git a/src/main/java/use_case/manage_application/ManageApplicationInputBoundary.java b/src/main/java/use_case/manage_application/ManageApplicationInputBoundary.java new file mode 100644 index 00000000..7edb4c24 --- /dev/null +++ b/src/main/java/use_case/manage_application/ManageApplicationInputBoundary.java @@ -0,0 +1,29 @@ +//package use_case.manage_application; +// +///** +// * Input Boundary for actions which are related to logging in. +// */ +// +///// // DONE ////// +//public interface ManageApplicationInputBoundary { +// // note that this is an interface so there isn't implementation of methods +// +// /** +// * Executes the manage application use case. +// */ +// +// void execute(); // doesn't require input from user +// +// // when clicked on an application: +//// /** +//// * Executes the switch to accept/reject view use case. +//// */ +//// void switchToProcessView();? +//} + + +package use_case.manage_application; + +public interface ManageApplicationInputBoundary { + void loadApplications(); +} diff --git a/src/main/java/use_case/manage_application/ManageApplicationInputData.java b/src/main/java/use_case/manage_application/ManageApplicationInputData.java new file mode 100644 index 00000000..79a65c46 --- /dev/null +++ b/src/main/java/use_case/manage_application/ManageApplicationInputData.java @@ -0,0 +1,6 @@ +package use_case.manage_application; + +public class ManageApplicationInputData { + // Empty because no input data is required for managing application + // Going to fetch all the applications info +} diff --git a/src/main/java/use_case/manage_application/ManageApplicationInteractor.java b/src/main/java/use_case/manage_application/ManageApplicationInteractor.java new file mode 100644 index 00000000..a18aa486 --- /dev/null +++ b/src/main/java/use_case/manage_application/ManageApplicationInteractor.java @@ -0,0 +1,90 @@ +//package use_case.manage_application; +// +//import use_case.login.LoginOutputBoundary; +//import use_case.login.LoginUserDataAccessInterface; +// +//public class ManageApplicationInteractor implements ManageApplicationInputBoundary { +// private final userDataAccessObject; +// private final ManageApplicationOutputBoundary managePresenter; +// +// public ManageApplicationInteractor(ManageApplicationDataAccessInterface userDataAccessInterface, +// ManageApplicationOutputBoundary manageApplicationOutputBoundary) { +// this.userDataAccessObject = userDataAccessInterface; +// this.managePresenter = manageApplicationOutputBoundary; +// } +// +// +// // grab information from database +// +// // do http request, like for login logout +// +// @Override +// public void execute() { +// +// +//// final String username = loginInputData.getUsername(); +//// final String password = loginInputData.getPassword(); +//// if (!userDataAccessObject.existsByName(username)) { +//// loginPresenter.prepareFailView(username + ": Account does not exist."); +//// } +//// else { +//// final String pwd = userDataAccessObject.get(username).getPassword(); +//// if (!password.equals(pwd)) { +//// loginPresenter.prepareFailView("Incorrect password for \"" + username + "\"."); +//// } +//// else { +//// +//// final User user = userDataAccessObject.get(loginInputData.getUsername()); +//// +//// userDataAccessObject.setCurrentUsername(username); +//// +//// final LoginOutputData loginOutputData = new LoginOutputData(user.getName()); +// +// /// you are trying to do your logic here, and then define output data, +// /// pass it back into the prepare success view method in outputboundary at last +//// loginPresenter.prepareSuccessView(loginOutputData); +//// } +//// } +// } +// +//} +package use_case.manage_application; + +import java.util.ArrayList; +import java.util.List; + +public class ManageApplicationInteractor implements ManageApplicationInputBoundary { + + private final ManageApplicationOutputBoundary presenter; + + public ManageApplicationInteractor(ManageApplicationOutputBoundary presenter) { + this.presenter = presenter; + } + + @Override + public void loadApplications() { + + // Create placeholder applications (fake data) + List fakeList = new ArrayList<>(); + + fakeList.add(new ManageApplicationOutputData.ApplicationData( + "1", "Application 1", "Pending", "This is a placeholder." + )); + + fakeList.add(new ManageApplicationOutputData.ApplicationData( + "2", "Application 2", "Approved", "Another placeholder." + )); + + fakeList.add(new ManageApplicationOutputData.ApplicationData( + "3", "Application 3", "Rejected", "Yet another placeholder." + )); + + // Wrap it in output data + ManageApplicationOutputData outputData = + new ManageApplicationOutputData(fakeList); + + // Send to presenter → viewmodel → view + presenter.presentApplications(outputData); + } +} + diff --git a/src/main/java/use_case/manage_application/ManageApplicationOutputBoundary.java b/src/main/java/use_case/manage_application/ManageApplicationOutputBoundary.java new file mode 100644 index 00000000..8d10606f --- /dev/null +++ b/src/main/java/use_case/manage_application/ManageApplicationOutputBoundary.java @@ -0,0 +1,14 @@ +package use_case.manage_application; + +/** + * Input Boundary for actions which are related to logging in. + */ +public interface ManageApplicationOutputBoundary { + // note that this is an interface so there isn't implementation of methods + + /** + * Prepares the success view for the Manage Application Use Case + * @param outputData the output data + */ + void presentApplications(ManageApplicationOutputData outputData); +} diff --git a/src/main/java/use_case/manage_application/ManageApplicationOutputData.java b/src/main/java/use_case/manage_application/ManageApplicationOutputData.java new file mode 100644 index 00000000..9784a4ce --- /dev/null +++ b/src/main/java/use_case/manage_application/ManageApplicationOutputData.java @@ -0,0 +1,37 @@ +//package use_case.manage_application; +// +//public class ManageApplicationOutputData { +//} + + +package use_case.manage_application; + +import java.util.List; + +public class ManageApplicationOutputData { + + private final List apps; + + public ManageApplicationOutputData(List apps) { + this.apps = apps; + } + + public List getApps() { + return apps; + } + + public static class ApplicationData { + public final String id; + public final String title; + public final String status; + public final String subtitle; + + public ApplicationData(String id, String title, String status, String subtitle) { + this.id = id; + this.title = title; + this.status = status; + this.subtitle = subtitle; + } + } +} + diff --git a/src/main/java/use_case/manage_application/ManageApplicationUserDataAccessInterface.java b/src/main/java/use_case/manage_application/ManageApplicationUserDataAccessInterface.java new file mode 100644 index 00000000..5744054d --- /dev/null +++ b/src/main/java/use_case/manage_application/ManageApplicationUserDataAccessInterface.java @@ -0,0 +1,15 @@ +package use_case.manage_application; + +import use_case.login.LoginInputData; + +/** + * Input Boundary for actions which are related to logging in. + */ +public interface ManageApplicationUserDataAccessInterface { + + /** + * Executes the login use case. + * @param loginInputData the input data + */ + void execute(LoginInputData loginInputData); +} diff --git a/src/main/java/use_case/signup/SignupInputData.java b/src/main/java/use_case/signup/SignupInputData.java index 86c5e8ab..2565a6c2 100644 --- a/src/main/java/use_case/signup/SignupInputData.java +++ b/src/main/java/use_case/signup/SignupInputData.java @@ -5,16 +5,24 @@ */ public class SignupInputData { + private final String firstname; + private final String lastname; private final String username; private final String password; private final String repeatPassword; - public SignupInputData(String username, String password, String repeatPassword) { + public SignupInputData(String firstname, String lastname, String username, String password, String repeatPassword) { + this.firstname = firstname; + this.lastname = lastname; this.username = username; this.password = password; this.repeatPassword = repeatPassword; } + String getFirstname() {return firstname;} + + String getLastname() {return lastname;} + String getUsername() { return username; } diff --git a/src/main/java/use_case/signup/SignupInteractor.java b/src/main/java/use_case/signup/SignupInteractor.java index e384b72d..820cb0bf 100644 --- a/src/main/java/use_case/signup/SignupInteractor.java +++ b/src/main/java/use_case/signup/SignupInteractor.java @@ -34,7 +34,7 @@ else if ("".equals(signupInputData.getUsername())) { userPresenter.prepareFailView("Username cannot be empty"); } else { - final User user = userFactory.create(signupInputData.getUsername(), signupInputData.getPassword()); + final User user = userFactory.create("visitor", signupInputData.getUsername(), signupInputData.getPassword()); userDataAccessObject.save(user); final SignupOutputData signupOutputData = new SignupOutputData(user.getName()); diff --git a/src/main/java/use_case/submit_application/SubmitApplicationDataAccessInterface.java b/src/main/java/use_case/submit_application/SubmitApplicationDataAccessInterface.java new file mode 100644 index 00000000..6760cfd5 --- /dev/null +++ b/src/main/java/use_case/submit_application/SubmitApplicationDataAccessInterface.java @@ -0,0 +1,10 @@ +package use_case.submit_application; + +import entity.Application; +import entity.User; + +public interface SubmitApplicationDataAccessInterface { + + void save(Application application); + +} diff --git a/src/main/java/use_case/submit_application/SubmitInputBoundary.java b/src/main/java/use_case/submit_application/SubmitInputBoundary.java new file mode 100644 index 00000000..98b989eb --- /dev/null +++ b/src/main/java/use_case/submit_application/SubmitInputBoundary.java @@ -0,0 +1,9 @@ +package use_case.submit_application; + +public interface SubmitInputBoundary { + + void execute(SubmitInputData submitInputData); + + void switchToBrowserFilterView(); + +} diff --git a/src/main/java/use_case/submit_application/SubmitInputData.java b/src/main/java/use_case/submit_application/SubmitInputData.java new file mode 100644 index 00000000..9d3d14cb --- /dev/null +++ b/src/main/java/use_case/submit_application/SubmitInputData.java @@ -0,0 +1,88 @@ +package use_case.submit_application; + +public class SubmitInputData { + private final String petId; + private final String username; + private final String firstname; + private final String lastname; + private final String age; + private final String occupation; + private final String address; + private final String homeEvi; + private final String tel; + private final String email; + private final String reason; + private final String prevExp; + private final String availability; + + public SubmitInputData(String petId, String username, String firstname, String lastname, String age, + String occupation, String address, String homeEvi, String tel, String email, String reason, + String prevExp, String availability) { + this.petId = petId; + this.username = username; + this.firstname = firstname; + this.lastname = lastname; + this.age = age; + this.occupation = occupation; + this.address = address; + this.homeEvi = homeEvi; + this.tel = tel; + this.email = email; + this.reason = reason; + this.prevExp = prevExp; + this.availability = availability; + } + + public String getPetId() { + return petId; + } + + public String getUsername() { + return username; + } + + public String getFirstname() { + return firstname; + } + + public String getLastname() { + return lastname; + } + + public String getAge() { + return age; + } + + public String getOccupation() { + return occupation; + } + + public String getAddress() { + return address; + } + + public String getHomeEvi() { + return homeEvi; + } + + public String getTel() { + return tel; + } + + public String getEmail() { + return email; + } + + public String getReason() { + return reason; + } + + public String getPrevExp() { + return prevExp; + } + + public String getAvailability() { + return availability; + } + +} diff --git a/src/main/java/use_case/submit_application/SubmitInteractor.java b/src/main/java/use_case/submit_application/SubmitInteractor.java new file mode 100644 index 00000000..b9f1c375 --- /dev/null +++ b/src/main/java/use_case/submit_application/SubmitInteractor.java @@ -0,0 +1,57 @@ +package use_case.submit_application; + +import entity.Application; +import entity.Visitor; + +public class SubmitInteractor implements SubmitInputBoundary { + private final SubmitUserDataAccessInterface userDataAccessObject; + private final SubmitApplicationDataAccessInterface applicationDataAccessObject; + private final SubmitOutputBoundary submitPresenter; + private final Application application; + + public SubmitInteractor(SubmitUserDataAccessInterface userDataAccessInterface, + SubmitApplicationDataAccessInterface applicationDataAccessInterface, + SubmitOutputBoundary submitOutputBoundary, + Application application) { + this.userDataAccessObject = userDataAccessInterface; + this.applicationDataAccessObject = applicationDataAccessInterface; + this.submitPresenter = submitOutputBoundary; + this.application = application; + } + + @Override + public void execute(SubmitInputData submitInputData) { + if ("".equals(submitInputData.getUsername())|| + "".equals(submitInputData.getFirstname())|| + "".equals(submitInputData.getLastname())|| + "".equals(submitInputData.getAge())|| + "".equals(submitInputData.getOccupation())|| + "".equals(submitInputData.getAddress())|| + "".equals(submitInputData.getHomeEvi())|| + "".equals(submitInputData.getTel())|| + "".equals(submitInputData.getEmail())|| + "".equals(submitInputData.getReason())|| + "".equals(submitInputData.getPrevExp())|| + "".equals(submitInputData.getAvailability())) { + submitPresenter.prepareFailView("Some required fields are missing"); + } + else if (! userDataAccessObject.existsByName(submitInputData.getUsername())){ + submitPresenter.prepareFailView("Username not found"); + } + else { + final Visitor visitor = (Visitor)userDataAccessObject.get(submitInputData.getUsername()); + final Application application = new Application(visitor, submitInputData.getPetId(), + submitInputData.getReason(), submitInputData.getHomeEvi(), + submitInputData.getAvailability(), submitInputData.getPrevExp()); + applicationDataAccessObject.save(application); + submitPresenter.prepareSuccessView( + "Your application has been successfully submitted. " + + "We will review it and contact you shortly."); + } + } + + @Override + public void switchToBrowserFilterView() { + submitPresenter.switchToBrowserFilterView(); + } +} diff --git a/src/main/java/use_case/submit_application/SubmitOutputBoundary.java b/src/main/java/use_case/submit_application/SubmitOutputBoundary.java new file mode 100644 index 00000000..e7d4ab62 --- /dev/null +++ b/src/main/java/use_case/submit_application/SubmitOutputBoundary.java @@ -0,0 +1,11 @@ +package use_case.submit_application; + +public interface SubmitOutputBoundary { + + void prepareSuccessView(String successMessage); + + void prepareFailView(String errorMessage); + + void switchToBrowserFilterView(); + +} diff --git a/src/main/java/use_case/submit_application/SubmitOutputData.java b/src/main/java/use_case/submit_application/SubmitOutputData.java new file mode 100644 index 00000000..048e8d44 --- /dev/null +++ b/src/main/java/use_case/submit_application/SubmitOutputData.java @@ -0,0 +1,4 @@ +package use_case.submit_application; + +public class SubmitOutputData { +} diff --git a/src/main/java/use_case/submit_application/SubmitUserDataAccessInterface.java b/src/main/java/use_case/submit_application/SubmitUserDataAccessInterface.java new file mode 100644 index 00000000..f90302d9 --- /dev/null +++ b/src/main/java/use_case/submit_application/SubmitUserDataAccessInterface.java @@ -0,0 +1,10 @@ +package use_case.submit_application; + +import entity.User; + +public interface SubmitUserDataAccessInterface { + + boolean existsByName(String username); + + User get(String username); +} diff --git a/src/main/java/view/BrowseFilterView.java b/src/main/java/view/BrowseFilterView.java new file mode 100644 index 00000000..0c4c8675 --- /dev/null +++ b/src/main/java/view/BrowseFilterView.java @@ -0,0 +1,115 @@ +package view; + +import interface_adapter.browse_filter.BrowseFilterController; +import interface_adapter.browse_filter.BrowseFilterState; +import interface_adapter.browse_filter.BrowseFilterViewModel; + +import javax.swing.*; +import javax.swing.table.DefaultTableModel; +import java.awt.*; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.List; + +public class BrowseFilterView extends JFrame implements PropertyChangeListener { + + private final BrowseFilterController controller; + private final BrowseFilterViewModel viewModel; + + private final JTextField speciesField = new JTextField(20); + private final JTextField genderField = new JTextField(20); + private final JButton searchButton = new JButton("Search"); + private final JButton clearButton = new JButton("Clear Filters"); + + // TABLE version + private final DefaultTableModel tableModel = new DefaultTableModel( + new String[]{"Name", "Type", "Breed", "Gender"}, 0 + ); + private final JTable petTable = new JTable(tableModel); + + public BrowseFilterView(BrowseFilterController controller, BrowseFilterViewModel viewModel) { + this.controller = controller; + this.viewModel = viewModel; + + viewModel.addPropertyChangeListener(this); + + setTitle("Pet Adoption Portal - Browse & Filter"); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setSize(1000, 600); + setLocationRelativeTo(null); + + // ===== Filter Panel ===== + JPanel filterPanel = new JPanel(new GridBagLayout()); + GridBagConstraints gbc = new GridBagConstraints(); + gbc.insets = new Insets(5, 5, 5, 5); + gbc.anchor = GridBagConstraints.WEST; + + gbc.gridx = 0; gbc.gridy = 0; + filterPanel.add(new JLabel("Species:"), gbc); + + gbc.gridx = 1; + filterPanel.add(speciesField, gbc); + + gbc.gridx = 0; gbc.gridy = 1; + filterPanel.add(new JLabel("Gender:"), gbc); + + gbc.gridx = 1; + filterPanel.add(genderField, gbc); + + gbc.gridx = 0; gbc.gridy = 2; gbc.gridwidth = 2; + gbc.anchor = GridBagConstraints.CENTER; + + JPanel buttonPanel = new JPanel(); + buttonPanel.add(searchButton); + buttonPanel.add(clearButton); + filterPanel.add(buttonPanel, gbc); + + // ===== TABLE results with scroll ===== + JScrollPane scrollPane = new JScrollPane(petTable); + petTable.setRowHeight(28); + + getContentPane().setLayout(new BorderLayout()); + getContentPane().add(filterPanel, BorderLayout.NORTH); + getContentPane().add(scrollPane, BorderLayout.CENTER); + + // ===== Button Actions ===== + searchButton.addActionListener(e -> { + String species = speciesField.getText().trim(); + String gender = genderField.getText().trim(); + controller.execute(species, gender); + }); + + clearButton.addActionListener(e -> { + speciesField.setText(""); + genderField.setText(""); +// controller.execute("", ""); // reload all + + BrowseFilterState state = viewModel.getState(); + state.setPets(List.of()); + viewModel.firePropertyChange("pets"); + }); + + setVisible(true); + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + if ("pets".equals(evt.getPropertyName())) { + updateTable(viewModel.getState().getPets()); + } + } + + private void updateTable(List pets) { + tableModel.setRowCount(0); + + for (String line : pets) { + // "name | type | breed | gender" + String[] data = line.split("\\|"); + for (int i = 0; i < data.length; i++) { + data[i] = data[i].trim(); + } + tableModel.addRow(data); + } + } +} + diff --git a/src/main/java/view/ManageApplicationView.java b/src/main/java/view/ManageApplicationView.java new file mode 100644 index 00000000..e196fb2e --- /dev/null +++ b/src/main/java/view/ManageApplicationView.java @@ -0,0 +1,86 @@ +package view; + +import interface_adapter.manage_application.ManageApplicationViewModel; + +import javax.swing.*; +import java.awt.*; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + + +public class ManageApplicationView extends JPanel implements PropertyChangeListener { + + private final String viewName = "applications"; + private final ManageApplicationViewModel viewModel; + + // Container that holds all the cards + private final JPanel cardsPanel = new JPanel(); + + public ManageApplicationView(ManageApplicationViewModel viewModel) { + this.viewModel = viewModel; + this.viewModel.addPropertyChangeListener(this); + + setLayout(new BorderLayout()); + + JLabel title = new JLabel("Applications"); + title.setHorizontalAlignment(SwingConstants.CENTER); + title.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0)); + add(title, BorderLayout.NORTH); + + // Configure card list panel + cardsPanel.setLayout(new BoxLayout(cardsPanel, BoxLayout.Y_AXIS)); + cardsPanel.setBackground(Color.WHITE); + + // Scroll pane containing the cards + JScrollPane scrollPane = new JScrollPane(cardsPanel); + scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); + + add(scrollPane, BorderLayout.CENTER); + + // TEMP: Add 3 example empty cards to show the layout working + addPlaceholderCards(); + } + + // Add example empty cards so the UI renders before data exists. + private void addPlaceholderCards() { + for (int i = 0; i < 3; i++) { + cardsPanel.add(createApplicationCard("Application " + (i + 1))); + } + } + + //Creates a single card panel representing one application. + private JPanel createApplicationCard(String titleText) { + JPanel card = new JPanel(); + card.setLayout(new BoxLayout(card, BoxLayout.Y_AXIS)); + card.setBorder(BorderFactory.createCompoundBorder( + BorderFactory.createEmptyBorder(10, 10, 10, 10), + BorderFactory.createLineBorder(Color.GRAY, 1) + )); + card.setMaximumSize(new Dimension(Integer.MAX_VALUE, 120)); // full width + card.setBackground(Color.WHITE); + + JLabel title = new JLabel(titleText); + title.setFont(title.getFont().deriveFont(Font.BOLD, 16f)); + + JLabel details = new JLabel("Details go here..."); + details.setFont(details.getFont().deriveFont(12f)); + + card.add(title); + card.add(Box.createRigidArea(new Dimension(0, 5))); + card.add(details); + + return card; + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + // When ViewModel has new list → rebuild cards + // Eventually: render real application data + } + + public String getViewName() { + return viewName; + } +} + + diff --git a/src/main/java/view/SignupView.java b/src/main/java/view/SignupView.java index 1330c097..6e90ed4d 100644 --- a/src/main/java/view/SignupView.java +++ b/src/main/java/view/SignupView.java @@ -20,6 +20,8 @@ public class SignupView extends JPanel implements ActionListener, PropertyChange private final String viewName = "sign up"; private final SignupViewModel signupViewModel; + private final JTextField firstnameInputField = new JTextField(15); + private final JTextField lastnameInputField = new JTextField(15); private final JTextField usernameInputField = new JTextField(15); private final JPasswordField passwordInputField = new JPasswordField(15); private final JPasswordField repeatPasswordInputField = new JPasswordField(15); @@ -30,12 +32,16 @@ public class SignupView extends JPanel implements ActionListener, PropertyChange private final JButton toLogin; public SignupView(SignupViewModel signupViewModel) { - this.signupViewModel = signupViewModel; + this.signupViewModel = signupViewModel; //其实是ViewModel所以get state会得到signup state signupViewModel.addPropertyChangeListener(this); final JLabel title = new JLabel(SignupViewModel.TITLE_LABEL); title.setAlignmentX(Component.CENTER_ALIGNMENT); + final LabelTextPanel firstnameInfo = new LabelTextPanel( + new JLabel(SignupViewModel.FIRSTNAME_LABEL), firstnameInputField); + final LabelTextPanel lastnameInfo = new LabelTextPanel( + new JLabel(SignupViewModel.LASTNAME_LABEL), lastnameInputField); final LabelTextPanel usernameInfo = new LabelTextPanel( new JLabel(SignupViewModel.USERNAME_LABEL), usernameInputField); final LabelTextPanel passwordInfo = new LabelTextPanel( @@ -56,9 +62,11 @@ public SignupView(SignupViewModel signupViewModel) { new ActionListener() { public void actionPerformed(ActionEvent evt) { if (evt.getSource().equals(signUp)) { - final SignupState currentState = signupViewModel.getState(); + final SignupState currentState = signupViewModel.getState(); //取出用户输入的所有注册信息 signupController.execute( + currentState.getFirstname(), + currentState.getLastname(), currentState.getUsername(), currentState.getPassword(), currentState.getRepeatPassword() @@ -78,6 +86,8 @@ public void actionPerformed(ActionEvent evt) { cancel.addActionListener(this); + addFirstnameListener(); + addLastnameListener(); addUsernameListener(); addPasswordListener(); addRepeatPasswordListener(); @@ -85,12 +95,54 @@ public void actionPerformed(ActionEvent evt) { this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); this.add(title); + this.add(firstnameInfo); + this.add(lastnameInfo); this.add(usernameInfo); this.add(passwordInfo); this.add(repeatPasswordInfo); this.add(buttons); } + private void addFirstnameListener() { + firstnameInputField.getDocument().addDocumentListener(new DocumentListener() { + + private void documentListenerHelper() { + final SignupState currentState = signupViewModel.getState(); + currentState.setFirstname(firstnameInputField.getText()); + signupViewModel.setState(currentState); + } + + @Override + public void insertUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void removeUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void changedUpdate(DocumentEvent e) {documentListenerHelper();} + }); + } + + private void addLastnameListener() { + lastnameInputField.getDocument().addDocumentListener(new DocumentListener() { + + private void documentListenerHelper() { + final SignupState currentState = signupViewModel.getState(); + currentState.setLastname(lastnameInputField.getText()); + signupViewModel.setState(currentState); + } + + @Override + public void insertUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void removeUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void changedUpdate(DocumentEvent e) {documentListenerHelper();} + }); + } + private void addUsernameListener() { usernameInputField.getDocument().addDocumentListener(new DocumentListener() { diff --git a/src/main/java/view/SubmitView.java b/src/main/java/view/SubmitView.java new file mode 100644 index 00000000..442c337e --- /dev/null +++ b/src/main/java/view/SubmitView.java @@ -0,0 +1,407 @@ +package view; + +import interface_adapter.signup.SignupState; +import interface_adapter.submit_application.SubmitController; +import interface_adapter.submit_application.SubmitState; +import interface_adapter.submit_application.SubmitViewModel; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; + +public class SubmitView extends JPanel implements ActionListener, PropertyChangeListener { + final String viewName = "Submit"; + private final SubmitViewModel submitViewModel; + + private final JTextField usernameInputField = new JTextField(15); + private final JTextField firstnameInputField = new JTextField(15); + private final JTextField lastnameInputField = new JTextField(15); + private final JTextField ageInputField = new JTextField(3); + private final JTextField occupationInputField = new JTextField(15); + private final JTextField addressInputField = new JTextField(100); + private final JTextField homeEviInputField = new JTextField(200); + private final JTextField telInputField = new JTextField(20); + private final JTextField emailInputField = new JTextField(30); + private final JTextField reasonInputField = new JTextField(200); + private final JTextField prevExpInputField = new JTextField(100); + private final JTextField availabilityInputField = new JTextField(100); + private SubmitController submitController = null; + + private final JButton submit; + private final JButton cancel; + + public SubmitView(SubmitViewModel submitViewModel) { + this.submitViewModel = submitViewModel; + submitViewModel.addPropertyChangeListener(this); + + final JLabel title = new JLabel(SubmitViewModel.TITLE_LABEL); + title.setAlignmentX(Component.CENTER_ALIGNMENT); + + final LabelTextPanel usernameInfo = new LabelTextPanel( + new JLabel(SubmitViewModel.USERNAME_LABEL), usernameInputField); + final LabelTextPanel firstnameInfo = new LabelTextPanel( + new JLabel(SubmitViewModel.FIRSTNAME_LABEL), firstnameInputField); + final LabelTextPanel lastnameInfo = new LabelTextPanel( + new JLabel(SubmitViewModel.LASTNAME_LABEL), lastnameInputField); + final LabelTextPanel ageInfo = new LabelTextPanel( + new JLabel(SubmitViewModel.AGE_LABEL), ageInputField); + final LabelTextPanel occupationInfo = new LabelTextPanel( + new JLabel(SubmitViewModel.OCCUPATION_LABEL), occupationInputField); + final LabelTextPanel addressInfo = new LabelTextPanel( + new JLabel(SubmitViewModel.ADDRESS_LABEL), addressInputField); + final LabelTextPanel telInfo = new LabelTextPanel( + new JLabel(SubmitViewModel.TEL_LABEL), telInputField); + final LabelTextPanel emailInfo = new LabelTextPanel( + new JLabel(SubmitViewModel.EMAIL_LABEL), emailInputField); + + final JPanel homeEviInfo = new JPanel(); + homeEviInfo.setLayout(new BoxLayout(homeEviInfo, BoxLayout.Y_AXIS)); + homeEviInfo.add(new JLabel(SubmitViewModel.HOME_LABEL)); + homeEviInfo.add(homeEviInputField); + + final JPanel reasonInfo = new JPanel(); + reasonInfo.setLayout(new BoxLayout(reasonInfo, BoxLayout.Y_AXIS)); + reasonInfo.add(new JLabel(SubmitViewModel.REASON_LABEL)); + reasonInfo.add(reasonInputField); + + final JPanel prevExpInfo = new JPanel(); + prevExpInfo.setLayout(new BoxLayout(prevExpInfo, BoxLayout.Y_AXIS)); + prevExpInfo.add(new JLabel(SubmitViewModel.EXP_LABEL)); + prevExpInfo.add(prevExpInputField); + + final JPanel availabilityInfo = new JPanel(); + availabilityInfo.setLayout(new BoxLayout(availabilityInfo, BoxLayout.Y_AXIS)); + prevExpInfo.add(new JLabel(SubmitViewModel.AVAILABILITY_LABEL)); + prevExpInfo.add(availabilityInputField); + + final JPanel buttons = new JPanel(); + submit = new JButton(SubmitViewModel.SUBMIT_BUTTON_LABEL); + buttons.add(submit); + cancel = new JButton(SubmitViewModel.CANCEL_BUTTON_LABEL); + buttons.add(cancel); + + submit.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent evt) { + if (evt.getSource().equals(submit)) { + final SubmitState currentState = submitViewModel.getState(); + + submitController.execute( + currentState.getPetId(), + currentState.getUsername(), + currentState.getFirstname(), + currentState.getLastname(), + currentState.getAge(), + currentState.getOccupation(), + currentState.getAddress(), + currentState.getHomeEvi(), + currentState.getTel(), + currentState.getEmail(), + currentState.getReason(), + currentState.getPrevExp(), + currentState.getAvailability() + ); + + JOptionPane.showMessageDialog(SubmitView.this, + "Your application has been successfully submitted!"); + + } + } + } + ); + + cancel.addActionListener( + new ActionListener() { + public void actionPerformed(ActionEvent evt) { + submitController.switchToBrowserFilterView(); + } + }); + + addUsernameListener(); + addFirstnameListener(); + addLastnameListener(); + addAgeListener(); + addOccupationListener(); + addAddressListener(); + addHomeListener(); + addTelListener(); + addEmailListener(); + addReasonListener(); + addExpListener(); + addAvailabilityListener(); + + this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); + + this.add(title); + this.add(usernameInfo); + this.add(firstnameInfo); + this.add(lastnameInfo); + this.add(ageInfo); + this.add(occupationInfo); + this.add(addressInfo); + this.add(telInfo); + this.add(emailInfo); + this.add(reasonInfo); + this.add(prevExpInfo); + this.add(availabilityInfo); + this.add(buttons); + } + + private void addUsernameListener() { + usernameInputField.getDocument().addDocumentListener(new DocumentListener() { + + private void documentListenerHelper() { + final SubmitState currentState = submitViewModel.getState(); + currentState.setUsername(usernameInputField.getText()); + submitViewModel.setState(currentState); + } + @Override + public void insertUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void removeUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void changedUpdate(DocumentEvent e) {documentListenerHelper();} + }); + } + + private void addFirstnameListener() { + firstnameInputField.getDocument().addDocumentListener(new DocumentListener() { + + private void documentListenerHelper() { + final SubmitState currentState = submitViewModel.getState(); + currentState.setFirstname(firstnameInputField.getText()); + submitViewModel.setState(currentState); + } + @Override + public void insertUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void removeUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void changedUpdate(DocumentEvent e) {documentListenerHelper();} + }); + } + + private void addLastnameListener() { + lastnameInputField.getDocument().addDocumentListener(new DocumentListener() { + + private void documentListenerHelper() { + final SubmitState currentState = submitViewModel.getState(); + currentState.setLastname(lastnameInputField.getText()); + submitViewModel.setState(currentState); + } + @Override + public void insertUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void removeUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void changedUpdate(DocumentEvent e) {documentListenerHelper();} + }); + } + + private void addAgeListener() { + ageInputField.getDocument().addDocumentListener(new DocumentListener() { + + private void documentListenerHelper() { + final SubmitState currentState = submitViewModel.getState(); + currentState.setAge(ageInputField.getText()); + submitViewModel.setState(currentState); + } + @Override + public void insertUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void removeUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void changedUpdate(DocumentEvent e) {documentListenerHelper();} + }); + } + + private void addOccupationListener() { + occupationInputField.getDocument().addDocumentListener(new DocumentListener() { + + private void documentListenerHelper() { + final SubmitState currentState = submitViewModel.getState(); + currentState.setOccupation(occupationInputField.getText()); + submitViewModel.setState(currentState); + } + @Override + public void insertUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void removeUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void changedUpdate(DocumentEvent e) {documentListenerHelper();} + }); + } + + private void addAddressListener() { + addressInputField.getDocument().addDocumentListener(new DocumentListener() { + + private void documentListenerHelper() { + final SubmitState currentState = submitViewModel.getState(); + currentState.setAddress(addressInputField.getText()); + submitViewModel.setState(currentState); + } + @Override + public void insertUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void removeUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void changedUpdate(DocumentEvent e) {documentListenerHelper();} + }); + } + + private void addHomeListener() { + homeEviInputField.getDocument().addDocumentListener(new DocumentListener() { + + private void documentListenerHelper() { + final SubmitState currentState = submitViewModel.getState(); + currentState.setHomeEvi(homeEviInputField.getText()); + submitViewModel.setState(currentState); + } + @Override + public void insertUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void removeUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void changedUpdate(DocumentEvent e) {documentListenerHelper();} + }); + } + + private void addTelListener() { + telInputField.getDocument().addDocumentListener(new DocumentListener() { + + private void documentListenerHelper() { + final SubmitState currentState = submitViewModel.getState(); + currentState.setTel(telInputField.getText()); + submitViewModel.setState(currentState); + } + @Override + public void insertUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void removeUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void changedUpdate(DocumentEvent e) {documentListenerHelper();} + }); + } + + private void addEmailListener() { + emailInputField.getDocument().addDocumentListener(new DocumentListener() { + + private void documentListenerHelper() { + final SubmitState currentState = submitViewModel.getState(); + currentState.setEmail(emailInputField.getText()); + submitViewModel.setState(currentState); + } + @Override + public void insertUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void removeUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void changedUpdate(DocumentEvent e) {documentListenerHelper();} + }); + } + + private void addReasonListener() { + reasonInputField.getDocument().addDocumentListener(new DocumentListener() { + + private void documentListenerHelper() { + final SubmitState currentState = submitViewModel.getState(); + currentState.setReason(reasonInputField.getText()); + submitViewModel.setState(currentState); + } + @Override + public void insertUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void removeUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void changedUpdate(DocumentEvent e) {documentListenerHelper();} + }); + } + + private void addExpListener() { + prevExpInputField.getDocument().addDocumentListener(new DocumentListener() { + + private void documentListenerHelper() { + final SubmitState currentState = submitViewModel.getState(); + currentState.setPrevExp(prevExpInputField.getText()); + submitViewModel.setState(currentState); + } + @Override + public void insertUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void removeUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void changedUpdate(DocumentEvent e) {documentListenerHelper();} + }); + } + + private void addAvailabilityListener() { + availabilityInputField.getDocument().addDocumentListener(new DocumentListener() { + + private void documentListenerHelper() { + final SubmitState currentState = submitViewModel.getState(); + currentState.setAvailability(availabilityInputField.getText()); + submitViewModel.setState(currentState); + } + @Override + public void insertUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void removeUpdate(DocumentEvent e) {documentListenerHelper();} + + @Override + public void changedUpdate(DocumentEvent e) {documentListenerHelper();} + }); + } + + + @Override + public void actionPerformed(ActionEvent e) { + + } + + @Override + public void propertyChange(PropertyChangeEvent evt) { + final SubmitState state = (SubmitState) evt.getNewValue(); + if (state.getError() != null) { + JOptionPane.showMessageDialog(this, state.getError()); + } + if (state.getSuccess() != null) { + JOptionPane.showMessageDialog(this, state.getSuccess()); + } + } + + public String getViewName() { + return viewName; + } + + public void setSubmitController(SubmitController controller) { + this.submitController = controller; + } +} diff --git a/src/test/java/use_case/login/LoginInteractorTest.java b/src/test/java/use_case/login/LoginInteractorTest.java index 4662abd9..ba5b87c1 100644 --- a/src/test/java/use_case/login/LoginInteractorTest.java +++ b/src/test/java/use_case/login/LoginInteractorTest.java @@ -16,7 +16,7 @@ void successTest() { // For the success test, we need to add Paul to the data access repository before we log in. UserFactory factory = new UserFactory(); - User user = factory.create("Paul", "password"); + User user = factory.create("visitor","Paul", "password"); userRepository.save(user); // This creates a successPresenter that tests whether the test case is as we expect. @@ -46,7 +46,7 @@ void failurePasswordMismatchTest() { // For this failure test, we need to add Paul to the data access repository before we log in, and // the passwords should not match. UserFactory factory = new UserFactory(); - User user = factory.create("Paul", "password"); + User user = factory.create("visitor","Paul", "password"); userRepository.save(user); // This creates a presenter that tests whether the test case is as we expect. diff --git a/src/test/java/use_case/logout/LogoutInteractorTest.java b/src/test/java/use_case/logout/LogoutInteractorTest.java index e69fc341..d2766aa7 100644 --- a/src/test/java/use_case/logout/LogoutInteractorTest.java +++ b/src/test/java/use_case/logout/LogoutInteractorTest.java @@ -15,7 +15,7 @@ void successTest() { // For the success test, we need to add Paul to the data access repository before we log in. UserFactory factory = new UserFactory(); - User user = factory.create("Paul", "password"); + User user = factory.create("visitor","Paul", "password"); userRepository.save(user); userRepository.setCurrentUsername("Paul"); diff --git a/src/test/java/use_case/signup/SignupInteractorTest.java b/src/test/java/use_case/signup/SignupInteractorTest.java index adf75c28..085dcd69 100644 --- a/src/test/java/use_case/signup/SignupInteractorTest.java +++ b/src/test/java/use_case/signup/SignupInteractorTest.java @@ -73,7 +73,7 @@ void failureUserExistsTest() { // Add Paul to the repo so that when we check later they already exist UserFactory factory = new UserFactory(); - User user = factory.create("Paul", "pwd"); + User user = factory.create("visitor","Paul", "pwd"); userRepository.save(user); // This creates a presenter that tests whether the test case is as we expect.