Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion js/src/features/member-profile/api/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ export const memberProfileSchema = z.object({
referralSource: z
.string()
.max(200, "Referral source must be 200 characters or fewer."),
matchingPref: z.string(),
matchPref: z.string(),
industryPref: z.string(),
rolePref: z
.string()
Expand Down
2 changes: 1 addition & 1 deletion js/src/features/member-profile/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export interface MemberProfileValues {
linkedInUrl: string;
introduction: string;
referralSource: string;
matchingPref: string;
matchPref: string;
industryPref: string;
rolePref: string;
topics: string;
Expand Down
36 changes: 24 additions & 12 deletions js/src/features/sign-up/components/SignUpForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import {
import { useState } from "react";

// Options for select fields. Defined in SignUpFormConfig
const matchingPrefOptions = MATCHING_PREFERENCES.map((v) => ({
const matchingPreferenceOptions = MATCHING_PREFERENCES.map((v) => ({
Comment thread
Allimonae marked this conversation as resolved.
value: v,
label: v,
}));
Expand All @@ -33,7 +33,7 @@ const initialFormValues: MemberProfileValues = {
linkedInUrl: "",
introduction: "",
referralSource: "",
matchingPref: "",
matchPref: "",
industryPref: "",
rolePref: "",
topics: "",
Expand Down Expand Up @@ -122,12 +122,24 @@ export function SignUpForm() {

setIsSubmitting(true);
try {
// TODO: replace with API call
await Promise.resolve();
setSuccessMessage("Your form was submitted successfully.");
const response = await fetch("/api/members", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(values),
});
if (response.ok) {
setSuccessMessage("Your form was submitted successfully.");
setValues({ ...initialFormValues });
} else {
const data = await response.json();
setSubmitError(
data.message ||
"An error occurred while submitting the form. Please try again later or contact an administrator.",
);
}
} catch (_error) {
setSubmitError(
"There was a problem submitting the form. Please try again.",
"Network error - please check your connection and try again",
);
} finally {
setIsSubmitting(false);
Expand Down Expand Up @@ -206,16 +218,16 @@ export function SignUpForm() {
<Select
label="Matching Preference"
placeholder="No Preference"
data={matchingPrefOptions}
value={values.matchingPref}
data={matchingPreferenceOptions}
value={values.matchPref}
onChange={(value) =>
handleFieldChange(
"matchingPref",
(value || "") as MemberProfileValues["matchingPref"],
"matchPref",
(value || "") as MemberProfileValues["matchPref"],
)
}
onBlur={() => handleFieldBlur("matchingPref")}
error={errors.matchingPref}
onBlur={() => handleFieldBlur("matchPref")}
error={errors.matchPref}
/>
<Select
label="What industry are you in, or looking to get into?"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,7 @@
import org.patinanetwork.patchats.api.member.dto.UpdateMemberRequest;
import org.patinanetwork.patchats.common.web.exception.MemberDuplicateException;
import org.patinanetwork.patchats.common.web.exception.MemberNotFoundException;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;

@Service
@RequiredArgsConstructor
Expand Down Expand Up @@ -58,9 +56,7 @@
.topics(request.topics())
.extraNotes(request.extraNotes())
.build();
Member updatedMember = memberRepo
.updateMember(member)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Member not found"));
Member updatedMember = memberRepo.updateMember(member).orElseThrow(() -> new MemberNotFoundException(id));
return MemberDto.from(updatedMember);
}

Expand All @@ -72,9 +68,9 @@
// .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Member not found"));
// }

// public MemberDto deactivateMemberById(UUID id) {
// public MemberDto deactivateMember(UUID id) {

Check warning on line 71 in src/main/java/org/patinanetwork/patchats/api/member/MemberService.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

This block of commented-out lines of code should be removed.

See more on https://sonarcloud.io/project/issues?id=Patina-Network_patchats&issues=AZ-5JU9ZpapJ23NeH3vH&open=AZ-5JU9ZpapJ23NeH3vH&pullRequest=60
// return memberRepo
// .deactivateMemberById(id)
// .deactivateMember(id)
// .map(MemberDto::from)
// .orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Member not found"));
// }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.patinanetwork.patchats.api.member.db.models;

import java.time.Instant;
import java.time.OffsetDateTime;
import java.util.UUID;
import lombok.Builder;
import lombok.EqualsAndHashCode;
Expand All @@ -10,6 +10,7 @@

@Getter
@Builder
@Setter
@ToString
@EqualsAndHashCode
public class Member {
Expand Down Expand Up @@ -49,7 +50,7 @@ public class Member {
@Setter
private String extraNotes;

private Instant createdAt;
private OffsetDateTime createdAt;

private Instant updatedAt;
private OffsetDateTime updatedAt;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.OffsetDateTime;
import java.util.Optional;
import java.util.UUID;
import lombok.RequiredArgsConstructor;
Expand Down Expand Up @@ -29,8 +30,8 @@ private Member parseResultSetToMember(final ResultSet rs) throws SQLException {
.rolePref(rs.getString("role_pref"))
.topics(rs.getString("topics"))
.extraNotes(rs.getString("extra_notes"))
.createdAt(rs.getTimestamp("created_at").toInstant())
.updatedAt(rs.getTimestamp("updated_at").toInstant())
.createdAt(rs.getObject("created_at", OffsetDateTime.class))
.updatedAt(rs.getObject("updated_at", OffsetDateTime.class))
.build();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.patinanetwork.patchats.api.member.dto;

import io.swagger.v3.oas.annotations.media.Schema;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.util.UUID;
import lombok.Builder;
import lombok.EqualsAndHashCode;
Expand Down Expand Up @@ -53,10 +53,10 @@ public class MemberDto {
private String extraNotes;

@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private Instant createdAt;
private OffsetDateTime createdAt;

@Schema(requiredMode = Schema.RequiredMode.REQUIRED)
private Instant updatedAt;
private OffsetDateTime updatedAt;

public static MemberDto from(final Member member) {
return MemberDto.builder()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package org.patinanetwork.patchats.api.member;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import java.util.UUID;
import org.junit.jupiter.api.Test;
import org.patinanetwork.patchats.api.member.dto.CreateMemberRequest;
import org.patinanetwork.patchats.api.member.dto.MemberDto;
import org.patinanetwork.patchats.common.web.ApiExceptionHandler;
import org.patinanetwork.patchats.common.web.exception.MemberDuplicateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc;

@WebMvcTest(MemberController.class)
@AutoConfigureMockMvc(addFilters = false)
@Import(ApiExceptionHandler.class)
class MemberControllerTest {

@Autowired
private MockMvc mockMvc;

@MockitoBean
private MemberService memberService;

@Test
void createMember_ReturnsOkAndMemberDto() throws Exception {
final CreateMemberRequest request = new CreateMemberRequest(
"John Doe",
"john.doe@example.com",
"https://www.linkedin.com/in/johndoe",
"Hello, I'm John!",
"Friend",
"Mentor - I am looking for guidance from someone with more experience",
"Technology",
"Software Engineer",
"College, Career Development",
"I want to be meet someone in person in NYC");

when(memberService.createMember(any()))
.thenReturn(MemberDto.builder()
.id(UUID.randomUUID())
.fullName(request.fullName())
.email(request.email())
.linkedInUrl(request.linkedInUrl())
.introduction(request.introduction())
.referralSource(request.referralSource())
.active(true)
.matchPref(request.matchPref())
.industryPref(request.industryPref())
.rolePref(request.rolePref())
.topics(request.topics())
.extraNotes(request.extraNotes())
.build());
mockMvc.perform(
post("/api/members")
.contentType(MediaType.APPLICATION_JSON)
.content(
"{\"fullName\":\"John Doe\",\"email\":\"john.doe@example.com\",\"linkedInUrl\":\"https://www.linkedin.com/in/johndoe\",\"introduction\":\"Hello, I'm John!\",\"referralSource\":\"Friend\",\"matchPref\":\"Mentor - I am looking for guidance from someone with more experience\",\"industryPref\":\"Technology\",\"rolePref\":\"Software Engineer\",\"topics\":\"College, Career Development\",\"extraNotes\":\"I want to be meet someone in person in NYC\"}"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.success").value(true))
.andExpect(jsonPath("$.payload.fullName").value(request.fullName()))
.andExpect(jsonPath("$.payload.email").value(request.email()))
.andExpect(jsonPath("$.payload.linkedInUrl").value(request.linkedInUrl()))
.andExpect(jsonPath("$.payload.introduction").value(request.introduction()))
.andExpect(jsonPath("$.payload.referralSource").value(request.referralSource()))
.andExpect(jsonPath("$.payload.matchPref").value(request.matchPref()))
.andExpect(jsonPath("$.payload.industryPref").value(request.industryPref()))
.andExpect(jsonPath("$.payload.rolePref").value(request.rolePref()))
.andExpect(jsonPath("$.payload.topics").value(request.topics()))
.andExpect(jsonPath("$.payload.extraNotes").value(request.extraNotes()))
.andExpect(jsonPath("$.payload.id").isNotEmpty())
.andExpect(jsonPath("$.payload.active").value(true));
}

@Test
void createMember_returnsBadRequestWhenFullNameIsBlank() throws Exception {
mockMvc.perform(
post("/api/members")
.contentType(MediaType.APPLICATION_JSON)
.content(
"{\"fullName\":\"\",\"email\":\"john.doe@example.com\",\"linkedInUrl\":\"https://www.linkedin.com/in/johndoe\",\"introduction\":\"Hello, I'm John!\",\"referralSource\":\"Friend\",\"matchPref\":\"Mentor - I am looking for guidance from someone with more experience\",\"industryPref\":\"Technology\",\"rolePref\":\"Software Engineer\",\"topics\":\"College, Career Development\",\"extraNotes\":\"I want to be meet someone in person in NYC\"}"))
.andExpect(status().isBadRequest())
.andExpect(jsonPath("$.success").value(false));
}

@Test
void createMember_returnsConflictOnDuplicateEmail() throws Exception {
when(memberService.createMember(any())).thenThrow(new MemberDuplicateException("john.doe@example.com"));
mockMvc.perform(
post("/api/members")
.contentType(MediaType.APPLICATION_JSON)
.content(
"{\"fullName\":\"John Doe\",\"email\":\"john.doe@example.com\",\"linkedInUrl\":\"https://www.linkedin.com/in/johndoe\",\"introduction\":\"Hello, I'm John!\",\"referralSource\":\"Friend\",\"matchPref\":\"Mentor - I am looking for guidance from someone with more experience\",\"industryPref\":\"Technology\",\"rolePref\":\"Software Engineer\",\"topics\":\"College, Career Development\",\"extraNotes\":\"I want to be meet someone in person in NYC\"}"))
.andExpect(status().isConflict())
.andExpect(jsonPath("$.success").value(false));
}
}
Loading
Loading