diff --git a/Backend.Tests/Services/StatisticsServiceTests.cs b/Backend.Tests/Services/StatisticsServiceTests.cs index 23e1e99713..789f884c2b 100644 --- a/Backend.Tests/Services/StatisticsServiceTests.cs +++ b/Backend.Tests/Services/StatisticsServiceTests.cs @@ -189,5 +189,43 @@ public void GetSemanticDomainUserCountsTestDomMatchesUser() var result = _statsService.GetSemanticDomainUserCounts(ProjId).Result; Assert.That(result.Find(uc => uc.Id == user.Id)!.WordCount, Is.EqualTo(wordCount)); } + + [Test] + public void GetSemanticDomainUserCountsTestRecentDomain() + { + var user = _userRepo.Create(GetUserWithProjId()).Result!; + + var olderDomain = new SemanticDomain + { + Id = "1.1.1", + Name = "Older Domain", + Created = "2023-01-01T10:00:00Z", + UserId = user.Id + }; + var newerDomain = new SemanticDomain + { + Id = "2.2.2", + Name = "Newer Domain", + Created = "2023-12-31T10:00:00Z", + UserId = user.Id + }; + var anonDomain = new SemanticDomain + { + Id = "3.3.3", + Name = "Unknown Domain" + }; + + var word1 = GetWordWithDomain(); + word1.Senses[0].SemanticDomains = [anonDomain, newerDomain]; + _wordRepo.AddFrontier(word1); + + var word2 = GetWordWithDomain(); + word2.Senses[0].SemanticDomains = [olderDomain]; + _wordRepo.AddFrontier(word2); + + var result = _statsService.GetSemanticDomainUserCounts(ProjId).Result; + var userCount = result.Find(uc => uc.Id == user.Id); + Assert.That(userCount?.RecentDomain, Is.EqualTo(newerDomain).UsingPropertiesComparer()); + } } } diff --git a/Backend/Models/Statistics.cs b/Backend/Models/Statistics.cs index 94197c380d..d41c344a5a 100644 --- a/Backend/Models/Statistics.cs +++ b/Backend/Models/Statistics.cs @@ -22,6 +22,7 @@ public class SemanticDomainUserCount public HashSet DomainSet { get; set; } public int DomainCount { get; set; } public int WordCount { get; set; } + public SemanticDomain? RecentDomain { get; set; } public SemanticDomainUserCount() { diff --git a/Backend/Services/StatisticsService.cs b/Backend/Services/StatisticsService.cs index d09c6e22db..2ad4d7a829 100644 --- a/Backend/Services/StatisticsService.cs +++ b/Backend/Services/StatisticsService.cs @@ -349,6 +349,18 @@ public async Task> GetSemanticDomainUserCounts(str } // update WordCount domainUserValue.WordCount++; + + // update RecentDomain if this domain has a more recent timestamp + if (!string.IsNullOrEmpty(sd.Created)) + { + if (domainUserValue.RecentDomain is null || + sd.Created.ParseModernPastDateTimePermissivelyWithException().CompareTo( + domainUserValue.RecentDomain.Created + .ParseModernPastDateTimePermissivelyWithException()) > 0) + { + domainUserValue.RecentDomain = sd.Clone(); + } + } } } } diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index 909612a9db..9668b40e59 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -587,6 +587,7 @@ "domainName": "Domain Name:", "username": "Username:", "domainCount": "Domains:", + "recentDomain": "Most Recent Domain:", "senseCount": "Words:" }, "axisLabel": { diff --git a/src/api/models/semantic-domain-user-count.ts b/src/api/models/semantic-domain-user-count.ts index cfbc6f7bd8..46edcd3649 100644 --- a/src/api/models/semantic-domain-user-count.ts +++ b/src/api/models/semantic-domain-user-count.ts @@ -12,6 +12,8 @@ * Do not edit the class manually. */ +import { SemanticDomain } from "./semantic-domain"; + /** * * @export @@ -48,4 +50,10 @@ export interface SemanticDomainUserCount { * @memberof SemanticDomainUserCount */ wordCount?: number; + /** + * + * @type {SemanticDomain} + * @memberof SemanticDomainUserCount + */ + recentDomain?: SemanticDomain; } diff --git a/src/components/Statistics/TableCells.tsx b/src/components/Statistics/TableCells.tsx index 5b08307735..cfdd85b3bb 100644 --- a/src/components/Statistics/TableCells.tsx +++ b/src/components/Statistics/TableCells.tsx @@ -1,5 +1,5 @@ import { TableCell, Typography } from "@mui/material"; -import { ReactElement } from "react"; +import { ReactElement, ReactNode } from "react"; import { useTranslation } from "react-i18next"; export function HeadCell(props: { titleId: string }): ReactElement { @@ -12,10 +12,16 @@ export function HeadCell(props: { titleId: string }): ReactElement { ); } -export function Cell(props: { text?: string | number | null }): ReactElement { +interface CellProps { + body?: ReactNode; + text?: string | number | null; +} + +export function Cell(props: CellProps): ReactElement { + const { body, text } = props; return ( - {props.text} + {body ? body : {text}} ); } diff --git a/src/components/Statistics/UserStatistics.tsx b/src/components/Statistics/UserStatistics.tsx index 69212b2b30..9e2d04d2d5 100644 --- a/src/components/Statistics/UserStatistics.tsx +++ b/src/components/Statistics/UserStatistics.tsx @@ -12,6 +12,7 @@ import { SemanticDomainUserCount } from "api/models"; import { getSemanticDomainUserCount } from "backend"; import * as LocalStorage from "backend/localStorage"; import { Cell, HeadCell } from "components/Statistics/TableCells"; +import DomainChip from "components/WordCard/DomainChip"; export default function UserStatistics(): ReactElement { const [domainUserCountList, setDomainUserCountList] = useState< @@ -40,6 +41,7 @@ export default function UserStatistics(): ReactElement { + @@ -48,6 +50,16 @@ export default function UserStatistics(): ReactElement { {domainUserCountList.map((t) => ( + + ) : null + } + />