Skip to content

Commit

Permalink
Merge pull request #50 from nora-kauczor/enhance-form
Browse files Browse the repository at this point in the history
Enhance ReviewDay
  • Loading branch information
nora-kauczor authored Nov 19, 2024
2 parents 9c0d8ee + a99d846 commit 5a60d8f
Show file tree
Hide file tree
Showing 9 changed files with 155 additions and 145 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,18 @@ private List<VocabIdsOfDate> getVocabIdsOfMonth(YearMonth yearMonth, Language la
}

public VocabIdsOfDate getVocabIdsOfDate(LocalDate date, Language language, String userName) {
List<String> ids = getVocabIdsOfDateAsList(date, language, userName);
return new VocabIdsOfDate(date, ids);
}

public List<String> getVocabIdsOfDateAsList(LocalDate date, Language language, String userName) {
List<Vocab> allVocabs = vocabRepo.findAll();
List<Vocab> vocabsOfDate = allVocabs.stream()
.filter(vocab -> vocab.getLanguage().equals(language))
.filter(vocab -> vocab.getDatesPerUser() != null && vocab.getDatesPerUser().containsKey(userName))
.filter(vocab -> vocab.getDatesPerUser().get(userName).stream()
.anyMatch(reviewDate -> reviewDate.equals(date))).toList();
List<String> ids = vocabsOfDate.stream().map(Vocab::getId).toList();
return new VocabIdsOfDate(date, ids);
.anyMatch(reviewDate -> reviewDate.equals(date))).toList();
return vocabsOfDate.stream().map(Vocab::getId).toList();
}

private VocabIdsOfDate[][] createEmptyCalendar() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@
public interface ReviewDayRepo extends MongoRepository<ReviewDay, String> {

ReviewDay getByDayAndUserIdAndLanguage(LocalDate day, String userId, Language language);


}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@


import lombok.RequiredArgsConstructor;
import org.example.backend.calendar.CalendarService;
import org.example.backend.exception.LanguageNotFoundException;

import org.example.backend.vocab.Language;
import org.example.backend.vocab.Vocab;

import org.example.backend.vocab.VocabService;

import org.springframework.stereotype.Service;

Expand All @@ -16,80 +14,57 @@
import java.util.*;



@RequiredArgsConstructor
@Service
public class ReviewDayService {

private final ReviewDayRepo reviewDayRepo;
private final VocabService vocabService;
private final CalendarService calendarService;

public ReviewDay getReviewDay(String languageString, String userId, LocalDate day) throws LanguageNotFoundException {
public ReviewDay getReviewDay(String languageString, String userId, LocalDate date) throws LanguageNotFoundException {
if (date.getDayOfMonth() == 1){clearReviewDayRepo();}
Language language = Language.getEnumByString(languageString);
Optional<ReviewDay> optionalReviewDay = Optional.ofNullable(reviewDayRepo.getByDayAndUserIdAndLanguage(day, userId, language));
List<String> idList = calendarService.getVocabIdsOfDateAsList (date, language, userId);
Optional<ReviewDay> optionalReviewDay = Optional.ofNullable(reviewDayRepo.getByDayAndUserIdAndLanguage (date, userId, language));
ReviewDay reviewDay = optionalReviewDay.map(oldReviewDay -> {
try {
return createReviewDay(oldReviewDay.id(), language, userId, day);
} catch (LanguageNotFoundException languageNotFoundException) {
throw new RuntimeException("Couldn't create ReviewDay because Language was not found.", languageNotFoundException);
}
}).orElseGet(() -> {
try {
return createReviewDay(language, userId, day);
} catch (LanguageNotFoundException languageNotFoundException) {
throw new RuntimeException("Couldn't create ReviewDay because Language was not found.", languageNotFoundException);
}
});
List<String> idsOfReviewedVocabs = oldReviewDay.idsOfVocabsToReview().entrySet().stream()
.filter(Map.Entry::getValue)
.map(Map.Entry::getKey)
.toList();
Map<String, Boolean> idMap = new HashMap<>();
for (String id : idList) {
if (idsOfReviewedVocabs.contains(id))
{idMap.put(id, true);} else {
idMap.put(id, false);
}
}
ReviewDay newReviewDay = new ReviewDay(oldReviewDay.id(), oldReviewDay.day(),
oldReviewDay.language(), oldReviewDay.userId(), idMap);
return reviewDayRepo.save(newReviewDay);
})
.orElseGet(() -> {
Map<String, Boolean> idMap = new HashMap<>();
for (String id : idList) {
idMap.put(id, false);
}
ReviewDay newReviewDay = new ReviewDay(null, date,
language, userId, idMap);
return reviewDayRepo.save(newReviewDay);
});
return reviewDayRepo.save(reviewDay);
}

public ReviewDay createReviewDay(String reviewDayId, Language language, String userId, LocalDate day) throws LanguageNotFoundException {
List<Vocab> allVocabsOfLanguage = vocabService.getAllVocabsOfLanguage(language.getStringOfEnum(), userId);
if (allVocabsOfLanguage.isEmpty()) {
return new ReviewDay(reviewDayId, day, language, userId, new HashMap<>());
}
List<Vocab> activeVocabs = allVocabsOfLanguage.stream()
.filter(vocab -> vocab.getDatesPerUser().containsKey(userId))
.toList();
if (activeVocabs.isEmpty()) {
return new ReviewDay(reviewDayId, day, language, userId, new HashMap<>());
}
List<Vocab> todaysVocabs = activeVocabs.stream()
.filter(vocab -> vocab.getDatesPerUser().get(userId).contains(day))
.toList();
Map<String, Boolean> idsToReview = new HashMap<>();
for (Vocab vocab : todaysVocabs) {
idsToReview.put(vocab.getId(), false);
}
return new ReviewDay(reviewDayId, day, language, userId, idsToReview);
}

public ReviewDay createReviewDay(Language language, String userId, LocalDate day) throws LanguageNotFoundException {
List<Vocab> allVocabsOfLanguage = vocabService.getAllVocabsOfLanguage(language.getStringOfEnum(), userId);
if (allVocabsOfLanguage.isEmpty()) {
return new ReviewDay(null, day, language, userId, new HashMap<>());
}
List<Vocab> activeVocabs = allVocabsOfLanguage.stream()
.filter(vocab -> vocab.getDatesPerUser().containsKey(userId))
.toList();
if (activeVocabs.isEmpty()) {
return new ReviewDay(null, day, language, userId, new HashMap<>());
}
List<Vocab> todaysVocabs = activeVocabs.stream()
.filter(vocab -> vocab.getDatesPerUser().get(userId).contains(day))
.toList();
Map<String, Boolean> idsToReview = new HashMap<>();
for (Vocab vocab : todaysVocabs) {
idsToReview.put(vocab.getId(), false);
}
return new ReviewDay(null, day, language, userId, idsToReview);
}

public ReviewDay setVocabReviewed(String vocabId, String languageString, String userId, LocalDate day) throws LanguageNotFoundException {
public ReviewDay setVocabReviewed(String vocabId, String languageString, String userId, LocalDate date) throws LanguageNotFoundException {
Language language = Language.getEnumByString(languageString);
Optional<ReviewDay> oldReviewDay = Optional.of(reviewDayRepo.getByDayAndUserIdAndLanguage(day, userId, language));
Optional<ReviewDay> oldReviewDay = Optional.of(reviewDayRepo.getByDayAndUserIdAndLanguage (date, userId, language));
Map<String, Boolean> newIdsOfVocabsToReview = oldReviewDay.get().idsOfVocabsToReview();
newIdsOfVocabsToReview.put(vocabId, true);
ReviewDay updatedReviewDay = new ReviewDay(oldReviewDay.get().id(), oldReviewDay.get().day(), language, userId, newIdsOfVocabsToReview);
return reviewDayRepo.save(updatedReviewDay);
}

public void clearReviewDayRepo(){
reviewDayRepo.deleteAll();
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package org.example.backend.review;

import org.example.backend.calendar.CalendarService;
import org.example.backend.exception.LanguageNotFoundException;
import org.example.backend.vocab.Language;
import org.example.backend.vocab.Vocab;
import org.example.backend.vocab.VocabService;
import org.junit.jupiter.api.Test;

import java.time.LocalDate;
Expand All @@ -17,24 +16,21 @@

class ReviewDayServiceTest {
private final ReviewDayRepo mockReviewRepo = mock(ReviewDayRepo.class);
private final VocabService mockVocabService = mock(VocabService.class);
private final ReviewDayService reviewService = new ReviewDayService(mockReviewRepo, mockVocabService);
private final CalendarService mockCalendarService = mock(CalendarService.class);
private final ReviewDayService reviewService = new ReviewDayService(mockReviewRepo, mockCalendarService);

@Test
void getReviewDay_shouldReturnReviewDayOfCurrentDate_ifItExists_whenCalled() throws LanguageNotFoundException {
LocalDate date = LocalDate.of(2025, 1, 1);
Map<String, List<LocalDate>> datesPerUser = new HashMap<>();
datesPerUser.put("user id", List.of(date));
Vocab testVocab = new Vocab("vocab id", "la prueba",
"test", "", Language.SPANISH, datesPerUser, "Wordio");
Map<String, Boolean> idsOfVocabsToReview = new HashMap<>();
idsOfVocabsToReview.put("vocab id", false);
idsOfVocabsToReview.put("vocab id 2", true);
ReviewDay expected = new ReviewDay(
"000", date, Language.SPANISH, "user id", idsOfVocabsToReview);
when(mockReviewRepo.getByDayAndUserIdAndLanguage(date, "user id", Language.SPANISH))
.thenReturn(expected);
when(mockVocabService.getAllVocabsOfLanguage("Spanish", "user id"))
.thenReturn(List.of(testVocab));
when(mockCalendarService.getVocabIdsOfDateAsList(date,Language.SPANISH, "user id"))
.thenReturn(List.of("vocab id", "vocab id 2"));
when(mockReviewRepo.save(expected)).thenReturn(expected);
ReviewDay actual = reviewService.getReviewDay("Spanish", "user id", date);
assertEquals(expected, actual);
Expand All @@ -55,42 +51,6 @@ void getReviewDay_shouldThrowLanguageNotFoundException_whenCalledWithNonExistent
reviewService.getReviewDay("Esperanto", "user id", date));
}

@Test
void createReviewDay_shouldCreateANewReviewDay_whenCalledWithAReviewDayId() throws LanguageNotFoundException {
LocalDate date = LocalDate.of(2025, 1, 1);
Map<String, List<LocalDate>> datesPerUser = new HashMap<>();
datesPerUser.put("user id", List.of(date));
Vocab testVocab1 = new Vocab("vocab id", "la prueba",
"test", "", Language.SPANISH, datesPerUser, "Wordio");
Vocab testVocab2 = new Vocab("vocab id 2", "la prueba",
"test", "", Language.SPANISH, new HashMap<>(), "Wordio");
Map<String, Boolean> oldIdsOfVocabsToReview = new HashMap<>();
oldIdsOfVocabsToReview.put("vocab id", false);
oldIdsOfVocabsToReview.put("vocab id 2", false);
ReviewDay oldReviewDay = new ReviewDay("123", date,Language.SPANISH, "user id", oldIdsOfVocabsToReview);
when(mockVocabService.getAllVocabsOfLanguage("Spanish", "user id")).thenReturn(List.of(testVocab1, testVocab2));
Map<String, Boolean> idsOfVocabsToReview = new HashMap<>();
idsOfVocabsToReview.put("vocab id", false);
ReviewDay expected = new ReviewDay(null, date,Language.SPANISH, "user id", idsOfVocabsToReview);
ReviewDay actual = reviewService.createReviewDay(Language.SPANISH,"user id", date);
assertEquals(expected, actual);
}

@Test
void createReviewDay_shouldCreateANewReviewDay_whenCalledWithoutAReviewDayId() throws LanguageNotFoundException {
LocalDate date = LocalDate.of(2025, 1, 1);
Map<String, List<LocalDate>> datesPerUser = new HashMap<>();
datesPerUser.put("user id", List.of(date));
Vocab testVocab = new Vocab("vocab id", "la prueba",
"test", "", Language.SPANISH, datesPerUser, "Wordio");
when(mockVocabService.getAllVocabsOfLanguage("Spanish", "user id")).thenReturn(List.of(testVocab));
Map<String, Boolean> idsOfVocabsToReview = new HashMap<>();
idsOfVocabsToReview.put("vocab id", false);
ReviewDay expected = new ReviewDay(null, date,Language.SPANISH, "user id", idsOfVocabsToReview);
ReviewDay actual = reviewService.createReviewDay( Language.SPANISH,"user id", date);
assertEquals(expected, actual);
}


@Test
void setVocabReviewed_shouldSetBooleanToTrue_whenCalledWithIdOfVocab() throws LanguageNotFoundException {
Expand Down
24 changes: 18 additions & 6 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ function App() {
const [displayNewVocabsPopUp, setDisplayNewVocabsPopUp] = useState(false)
const navigate = useNavigate()

console.log(vocabsToReview)

useEffect(() => {
getUserId()
}, []);
Expand Down Expand Up @@ -58,7 +60,6 @@ function App() {
axios.get(`/api/vocab?language=${language}`)
.then(response => {
setVocabs(response.data)
console.log("Successfully updated vocabs state.")
})
.catch(error => console.error(error))
}
Expand Down Expand Up @@ -94,6 +95,7 @@ function App() {
response.data.idsOfVocabsToReview)
.filter(innerArray => innerArray[1] === false)
.map(innerArray => innerArray[0]);
console.log(response.data)
if (vocabs.length < 1) {
console.error(
"Couldn't get vocabs to review because vocabs was empty.");
Expand All @@ -104,7 +106,6 @@ function App() {
})
.filter((vocab): vocab is Vocab => vocab !== undefined)
setVocabsToReview(vocabsToReview as Vocab[])
console.log("Successfully updated vocabsToReview state.")
}
})
.catch(error => {
Expand All @@ -119,18 +120,23 @@ function App() {
axios.put(`/api/review/${id}?language=${language}`)
.then(() => {
console.log(`Vocab with ID ${id} was marked as reviewed for today.`)
getAllVocabsOfLanguage()
// setTimeout(() => {
getVocabsToReview()
// }, 10000);
})
.catch(error => {
console.error(error)
})
}

function activateVocab(id: string): void {
if (toast.isActive(`activate-vocab-${id}`)) {
return;
}
axios.put(`api/vocab/activate/${id}`)
.then(() => {
console.log(`Successfully activated vocab with ID ${id}.`)
toast.success("Vocab successfully activated.")
toast.success("Vocab successfully activated.", { toastId: `activate-vocab-${id}` })
getAllVocabsOfLanguage()
})
.catch(error => {
Expand All @@ -140,10 +146,13 @@ function App() {
}

function deactivateVocab(id: string): void {
if (toast.isActive(`deactivate-vocab-${id}`)) {
return;
}
axios.put(`api/vocab/deactivate/${id}`)
.then(() => {
console.log(`Successfully deactivated vocab with ID ${id}.`)
toast.success("Vocab successfully deactivated.")
toast.success("Vocab successfully deactivated.", { toastId: `deactivate-vocab-${id}` })
getAllVocabsOfLanguage()
})
.catch(error => {
Expand All @@ -169,10 +178,13 @@ function App() {
}

function deleteVocab(id: string): void {
if (toast.isActive(`delete-vocab-${id}`)) {
return;
}
axios.delete(`api/vocab/${id}`)
.then(() => {
console.log(`Successfully deleted vocab with ID ${id}.`)
toast.success("Vocab successfully deleted")
toast.success("Vocab successfully deleted", { toastId: `delete-vocab-${id}` })
getAllVocabsOfLanguage()
})
.catch(error => {
Expand Down
18 changes: 14 additions & 4 deletions frontend/src/components/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import './Header.css'
import {useNavigate} from "react-router-dom";
import {useLocation, useNavigate, useParams} from "react-router-dom";
import {useEffect, useState} from "react";

type Props = {
userId: string
Expand All @@ -9,7 +10,15 @@ type Props = {
}

export default function Header(props: Readonly<Props>) {
const navigate = useNavigate()
// const [onReviewOrDisplayPage, setOnReviewOrDisplayPage] = useState(false)
const navigate = useNavigate()
// const location = useLocation();
// useEffect(() => {
// if (location.pathname === "/review" || location.pathname === "/display"){
// setOnReviewOrDisplayPage(true)
// }
// }, []);

function handleChange(event: React.ChangeEvent<HTMLSelectElement>){
props.setLanguage(event.target.value)
}
Expand All @@ -21,7 +30,9 @@ const navigate = useNavigate()
aria-live={"polite"}>
Wordio
</button>
{props.userId && props.language && (
{props.userId && props.language &&
// !onReviewOrDisplayPage &&
(
<div>
<label htmlFor={"select-language"} className={"visually-hidden"}>
Select your language
Expand All @@ -33,7 +44,6 @@ const navigate = useNavigate()
</select>
</div>
)}

{props.userId && <button id={"logout-button"}
onClick={props.logout}
aria-label={"Log out"}
Expand Down
1 change: 0 additions & 1 deletion frontend/src/components/VocabList/VocabList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ export default function VocabList(props: Readonly<Props>) {
props.deleteVocab(id)
}


return (<ul id={"vocab-list"} role={"list"}>
{props.vocabs.map(vocab => <li key={vocab.id}
className={`list-item card ${props.calendarMode ?
Expand Down
Loading

0 comments on commit 5a60d8f

Please sign in to comment.