diff --git a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/account/AuthenticationTokenController.java b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/account/AuthenticationTokenController.java index d237b1b..68c1a2f 100644 --- a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/account/AuthenticationTokenController.java +++ b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/account/AuthenticationTokenController.java @@ -47,7 +47,7 @@ @Controller public class AuthenticationTokenController { - private IAuthenticationTokenService authenticationTokenService; + private final IAuthenticationTokenService authenticationTokenService; public AuthenticationTokenController(IAuthenticationTokenService authenticationTokenService) { this.authenticationTokenService = Objects.requireNonNull(authenticationTokenService); @@ -59,10 +59,9 @@ public Connection authenticationTokens(@Argument int pag var edges = pageData.stream().map(authenticationToken -> { var value = new Relay().toGlobalId("AuthenticationToken", authenticationToken.id().toString()); var cursor = new DefaultConnectionCursor(value); - Edge edge = new DefaultEdge<>(authenticationToken, cursor); - return edge; + return (Edge) new DefaultEdge<>(authenticationToken, cursor); }).toList(); - var pageInfo = new PageInfoWithCount(null, null, false, false, pageData.getTotalElements()); + var pageInfo = new PageInfoWithCount(null, null, pageData.hasPrevious(), pageData.hasNext(), pageData.getTotalElements()); return new DefaultConnection<>(edges, pageInfo); } diff --git a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/activity/ActivityEntryController.java b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/activity/ActivityEntryController.java index 4380ee2..57d7c1d 100644 --- a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/activity/ActivityEntryController.java +++ b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/activity/ActivityEntryController.java @@ -24,6 +24,7 @@ import com.svalyn.studio.application.controllers.dto.ProfileDTO; import com.svalyn.studio.application.controllers.organization.dto.OrganizationDTO; import com.svalyn.studio.application.controllers.project.dto.ProjectDTO; +import com.svalyn.studio.application.controllers.viewer.Viewer; import com.svalyn.studio.application.services.activity.api.IActivityService; import graphql.relay.Connection; import graphql.relay.DefaultConnection; @@ -60,7 +61,7 @@ public Connection activityEntries(ProfileDTO profile, @Argumen Edge edge = new DefaultEdge<>(activityEntry, cursor); return edge; }).toList(); - var pageInfo = new PageInfoWithCount(null, null, false, false, pageData.getTotalElements()); + var pageInfo = new PageInfoWithCount(null, null, pageData.hasPrevious(), pageData.hasNext(), pageData.getTotalElements()); return new DefaultConnection<>(edges, pageInfo); } @@ -73,7 +74,7 @@ public Connection activityEntries(OrganizationDTO organization Edge edge = new DefaultEdge<>(activityEntry, cursor); return edge; }).toList(); - var pageInfo = new PageInfoWithCount(null, null, false, false, pageData.getTotalElements()); + var pageInfo = new PageInfoWithCount(null, null, pageData.hasPrevious(), pageData.hasNext(), pageData.getTotalElements()); return new DefaultConnection<>(edges, pageInfo); } @@ -86,7 +87,20 @@ public Connection activityEntries(ProjectDTO project, @Argumen Edge edge = new DefaultEdge<>(activityEntry, cursor); return edge; }).toList(); - var pageInfo = new PageInfoWithCount(null, null, false, false, pageData.getTotalElements()); + var pageInfo = new PageInfoWithCount(null, null, pageData.hasPrevious(), pageData.hasNext(), pageData.getTotalElements()); + return new DefaultConnection<>(edges, pageInfo); + } + + @SchemaMapping(typeName = "Viewer") + public Connection activityEntries(Viewer viewer, @Argument int page, @Argument int rowsPerPage) { + var pageData = this.activityService.findAllVisibleByUsername(viewer.username(), page, rowsPerPage); + var edges = pageData.stream().map(activityEntry -> { + var value = new Relay().toGlobalId("ActivityEntry", activityEntry.id().toString()); + var cursor = new DefaultConnectionCursor(value); + Edge edge = new DefaultEdge<>(activityEntry, cursor); + return edge; + }).toList(); + var pageInfo = new PageInfoWithCount(null, null, pageData.hasPrevious(), pageData.hasNext(), pageData.getTotalElements()); return new DefaultConnection<>(edges, pageInfo); } } diff --git a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/business/DomainController.java b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/business/DomainController.java index ec1d50b..f2d345a 100644 --- a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/business/DomainController.java +++ b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/business/DomainController.java @@ -61,7 +61,7 @@ public Connection domains(@Argument int page, @Argument int rowsPerPa Edge edge = new DefaultEdge<>(domain, cursor); return edge; }).toList(); - var pageInfo = new PageInfoWithCount(null, null, false, false, pageData.getTotalElements()); + var pageInfo = new PageInfoWithCount(null, null, pageData.hasPrevious(), pageData.hasNext(), pageData.getTotalElements()); return new DefaultConnection<>(edges, pageInfo); } } diff --git a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/history/BranchController.java b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/history/BranchController.java index a058470..c829910 100644 --- a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/history/BranchController.java +++ b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/history/BranchController.java @@ -58,7 +58,7 @@ public Connection branches(ProjectDTO project, @Argument int page, @A Edge edge = new DefaultEdge<>(branch, cursor); return edge; }).toList(); - var pageInfo = new PageInfoWithCount(null, null, false, false, pageData.getTotalElements()); + var pageInfo = new PageInfoWithCount(null, null, pageData.hasPrevious(), pageData.hasNext(), pageData.getTotalElements()); return new DefaultConnection<>(edges, pageInfo); } diff --git a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/history/ChangeController.java b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/history/ChangeController.java index b1e9fe9..b2b613d 100644 --- a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/history/ChangeController.java +++ b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/history/ChangeController.java @@ -78,8 +78,7 @@ public Connection changes(BranchDTO branch, @Argument int page, @Argu var edges = pageData.stream().map(change -> { var value = new Relay().toGlobalId("Change", change.id().toString()); var cursor = new DefaultConnectionCursor(value); - Edge edge = new DefaultEdge<>(change, cursor); - return edge; + return (Edge) new DefaultEdge<>(change, cursor); }).toList(); var pageInfo = new PageInfoWithCount(null, null, false, false, pageData.size()); return new DefaultConnection<>(edges, pageInfo); diff --git a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/history/ChangeProposalController.java b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/history/ChangeProposalController.java index 00d4dce..a2e4867 100644 --- a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/history/ChangeProposalController.java +++ b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/history/ChangeProposalController.java @@ -67,10 +67,9 @@ public Connection changeProposals(ProjectDTO project, @Argume var edges = pageData.stream().map(changeProposal -> { var value = new Relay().toGlobalId("ChangeProposal", changeProposal.id().toString()); var cursor = new DefaultConnectionCursor(value); - Edge edge = new DefaultEdge<>(changeProposal, cursor); - return edge; + return (Edge) new DefaultEdge<>(changeProposal, cursor); }).toList(); - var pageInfo = new PageInfoWithCount(null, null, false, false, pageData.getTotalElements()); + var pageInfo = new PageInfoWithCount(null, null, pageData.hasPrevious(), pageData.hasNext(), pageData.getTotalElements()); return new DefaultConnection<>(edges, pageInfo); } @@ -90,8 +89,7 @@ public Connection reviews(ChangeProposalDTO changeProposal) { var edges = pageData.stream().map(reviewDTO -> { var value = new Relay().toGlobalId("Review", reviewDTO.id().toString()); var cursor = new DefaultConnectionCursor(value); - Edge edge = new DefaultEdge<>(reviewDTO, cursor); - return edge; + return (Edge) new DefaultEdge<>(reviewDTO, cursor); }).toList(); var pageInfo = new PageInfoWithCount(null, null, false, false, pageData.size()); return new DefaultConnection<>(edges, pageInfo); diff --git a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/history/ChangeResourceController.java b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/history/ChangeResourceController.java index 89c5cf8..b252eda 100644 --- a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/history/ChangeResourceController.java +++ b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/history/ChangeResourceController.java @@ -61,8 +61,7 @@ public Connection resources(ChangeDTO change) { var edges = pageData.stream().map(changeResourceDTO -> { var value = new Relay().toGlobalId("ChangeResource", changeResourceDTO.id().toString()); var cursor = new DefaultConnectionCursor(value); - Edge edge = new DefaultEdge<>(changeResourceDTO, cursor); - return edge; + return (Edge) new DefaultEdge<>(changeResourceDTO, cursor); }).toList(); var pageInfo = new PageInfoWithCount(null, null, false, false, pageData.size()); return new DefaultConnection<>(edges, pageInfo); diff --git a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/notification/NotificationController.java b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/notification/NotificationController.java index e8a4ff5..e504da2 100644 --- a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/notification/NotificationController.java +++ b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/notification/NotificationController.java @@ -64,10 +64,9 @@ public Connection notifications(@Argument List { var value = new Relay().toGlobalId("Notification", notification.id().toString()); var cursor = new DefaultConnectionCursor(value); - Edge edge = new DefaultEdge<>(notification, cursor); - return edge; + return (Edge) new DefaultEdge<>(notification, cursor); }).toList(); - var pageInfo = new PageInfoWithCount(null, null, false, false, pageData.getTotalElements()); + var pageInfo = new PageInfoWithCount(null, null, pageData.hasPrevious(), pageData.hasNext(), pageData.getTotalElements()); return new DefaultConnection<>(edges, pageInfo); } diff --git a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/organization/InvitationController.java b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/organization/InvitationController.java index dd8ad46..bb5e068 100644 --- a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/organization/InvitationController.java +++ b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/organization/InvitationController.java @@ -61,10 +61,9 @@ public Connection invitations(@Argument int page, @Argument int r var edges = pageData.stream().map(invitation -> { var value = new Relay().toGlobalId("Invitation", invitation.id().toString()); var cursor = new DefaultConnectionCursor(value); - Edge edge = new DefaultEdge<>(invitation, cursor); - return edge; + return (Edge) new DefaultEdge<>(invitation, cursor); }).toList(); - var pageInfo = new PageInfoWithCount(null, null, false, false, pageData.getTotalElements()); + var pageInfo = new PageInfoWithCount(null, null, pageData.hasPrevious(), pageData.hasNext(), pageData.getTotalElements()); return new DefaultConnection<>(edges, pageInfo); } @@ -74,10 +73,9 @@ public Connection invitations(OrganizationDTO organization, @Argu var edges = pageData.stream().map(invitation -> { var value = new Relay().toGlobalId("Invitation", invitation.id().toString()); var cursor = new DefaultConnectionCursor(value); - Edge edge = new DefaultEdge<>(invitation, cursor); - return edge; + return (Edge) new DefaultEdge<>(invitation, cursor); }).toList(); - var pageInfo = new PageInfoWithCount(null, null, false, false, pageData.getTotalElements()); + var pageInfo = new PageInfoWithCount(null, null, pageData.hasPrevious(), pageData.hasNext(), pageData.getTotalElements()); return new DefaultConnection<>(edges, pageInfo); } diff --git a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/organization/MembershipController.java b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/organization/MembershipController.java index 957f074..0b86c37 100644 --- a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/organization/MembershipController.java +++ b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/organization/MembershipController.java @@ -59,10 +59,9 @@ public Connection memberships(OrganizationDTO organization, @Argu var edges = pageData.stream().map(membership -> { var value = new Relay().toGlobalId("Membership", membership.id().toString()); var cursor = new DefaultConnectionCursor(value); - Edge edge = new DefaultEdge<>(membership, cursor); - return edge; + return (Edge) new DefaultEdge<>(membership, cursor); }).toList(); - var pageInfo = new PageInfoWithCount(null, null, false, false, pageData.getTotalElements()); + var pageInfo = new PageInfoWithCount(null, null, pageData.hasPrevious(), pageData.hasNext(), pageData.getTotalElements()); return new DefaultConnection<>(edges, pageInfo); } diff --git a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/organization/OrganizationController.java b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/organization/OrganizationController.java index e5f9a52..d517b39 100644 --- a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/organization/OrganizationController.java +++ b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/organization/OrganizationController.java @@ -61,10 +61,9 @@ public Connection organizations() { var edges = page.stream().map(organization -> { var value = new Relay().toGlobalId("Organization", organization.identifier()); var cursor = new DefaultConnectionCursor(value); - Edge edge = new DefaultEdge<>(organization, cursor); - return edge; + return (Edge) new DefaultEdge<>(organization, cursor); }).toList(); - var pageInfo = new PageInfoWithCount(null, null, false, false, page.getTotalElements()); + var pageInfo = new PageInfoWithCount(null, null, page.hasPrevious(), page.hasNext(), page.getTotalElements()); return new DefaultConnection<>(edges, pageInfo); } diff --git a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/project/ProjectController.java b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/project/ProjectController.java index f29b25c..d460dd7 100644 --- a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/project/ProjectController.java +++ b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/project/ProjectController.java @@ -73,10 +73,9 @@ public Connection projects(OrganizationDTO organization, @Argument i var edges = pageData.stream().map(project -> { var value = new Relay().toGlobalId("Project", project.identifier()); var cursor = new DefaultConnectionCursor(value); - Edge edge = new DefaultEdge<>(project, cursor); - return edge; + return (Edge) new DefaultEdge<>(project, cursor); }).toList(); - var pageInfo = new PageInfoWithCount(null, null, false, false, pageData.getTotalElements()); + var pageInfo = new PageInfoWithCount(null, null, pageData.hasPrevious(), pageData.hasNext(), pageData.getTotalElements()); return new DefaultConnection<>(edges, pageInfo); } diff --git a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/tag/TagController.java b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/tag/TagController.java index 84f4ea4..8217649 100644 --- a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/tag/TagController.java +++ b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/controllers/tag/TagController.java @@ -61,10 +61,9 @@ public Connection tags(OrganizationDTO organization, @Argument int page, var edges = pageData.stream().map(tag -> { var value = new Relay().toGlobalId("Tag", tag.id().toString()); var cursor = new DefaultConnectionCursor(value); - Edge edge = new DefaultEdge<>(tag, cursor); - return edge; + return (Edge) new DefaultEdge<>(tag, cursor); }).toList(); - var pageInfo = new PageInfoWithCount(null, null, false, false, pageData.getTotalElements()); + var pageInfo = new PageInfoWithCount(null, null, pageData.hasPrevious(), pageData.hasNext(), pageData.getTotalElements()); return new DefaultConnection<>(edges, pageInfo); } @@ -79,10 +78,9 @@ public Connection tags(ProjectDTO project, @Argument int page, @Argument var edges = pageData.stream().map(tag -> { var value = new Relay().toGlobalId("Tag", tag.id().toString()); var cursor = new DefaultConnectionCursor(value); - Edge edge = new DefaultEdge<>(tag, cursor); - return edge; + return (Edge) new DefaultEdge<>(tag, cursor); }).toList(); - var pageInfo = new PageInfoWithCount(null, null, false, false, pageData.getTotalElements()); + var pageInfo = new PageInfoWithCount(null, null, pageData.hasPrevious(), pageData.hasNext(), pageData.getTotalElements()); return new DefaultConnection<>(edges, pageInfo); } diff --git a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/services/activity/ActivityService.java b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/services/activity/ActivityService.java index 35c5223..6621b1d 100644 --- a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/services/activity/ActivityService.java +++ b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/services/activity/ActivityService.java @@ -68,6 +68,18 @@ private Optional toDTO(ActivityEntry activityEntry) { createdBy)); } + @Override + @Transactional(readOnly = true) + public Page findAllVisibleByUsername(String username, int page, int rowsPerPage) { + return this.accountRepository.findByUsername(username).map(Account::getId).map(userId -> { + var activityEntries = this.activityEntryRepository.findAllVisibleByUserId(userId, page * rowsPerPage, rowsPerPage).stream() + .flatMap(entry -> this.toDTO(entry).stream()) + .toList(); + var count = this.activityEntryRepository.countAllByUserId(userId); + return new PageImpl<>(activityEntries, PageRequest.of(page, rowsPerPage), count); + }).orElse(new PageImpl<>(List.of())); + } + @Override @Transactional(readOnly = true) public Page findAllByUsername(String username, int page, int rowsPerPage) { diff --git a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/services/activity/api/IActivityService.java b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/services/activity/api/IActivityService.java index ecae087..7e442f6 100644 --- a/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/services/activity/api/IActivityService.java +++ b/backend/svalyn-studio-application/src/main/java/com/svalyn/studio/application/services/activity/api/IActivityService.java @@ -31,6 +31,8 @@ */ public interface IActivityService { + Page findAllVisibleByUsername(String username, int page, int rowsPerPage); + Page findAllByUsername(String username, int page, int rowsPerPage); Page findAllByOrganizationId(UUID organizationId, int page, int rowsPerPage); diff --git a/backend/svalyn-studio-application/src/main/resources/graphql/svalyn-studio.graphqls b/backend/svalyn-studio-application/src/main/resources/graphql/svalyn-studio.graphqls index 7697809..763a667 100644 --- a/backend/svalyn-studio-application/src/main/resources/graphql/svalyn-studio.graphqls +++ b/backend/svalyn-studio-application/src/main/resources/graphql/svalyn-studio.graphqls @@ -8,6 +8,8 @@ type Query { type PageInfo { count: Int! + hasPreviousPage: Boolean! + hasNextPage: Boolean! } type Viewer { @@ -26,6 +28,7 @@ type Viewer { authenticationTokens(page: Int!, rowsPerPage: Int!): ViewerAuthenticationTokensConnection! domains(page: Int!, rowsPerPage: Int!): ViewerDomainsConnection! domain(identifier: ID!): Domain + activityEntries(page: Int!, rowsPerPage: Int!): ViewerActivityEntriesConnection! } type ViewerInvitationsConnection { @@ -45,6 +48,15 @@ type ViewerOrganizationsEdge { node: Organization! } +type ViewerActivityEntriesConnection { + edges: [ViewerActivityEntriesEdge!]! + pageInfo: PageInfo! +} + +type ViewerActivityEntriesEdge { + node: ActivityEntry! +} + type Profile { name: String! username: String! diff --git a/backend/svalyn-studio-domain/src/main/java/com/svalyn/studio/domain/activity/repositories/IActivityEntryRepository.java b/backend/svalyn-studio-domain/src/main/java/com/svalyn/studio/domain/activity/repositories/IActivityEntryRepository.java index 9d98343..dd3f9a9 100644 --- a/backend/svalyn-studio-domain/src/main/java/com/svalyn/studio/domain/activity/repositories/IActivityEntryRepository.java +++ b/backend/svalyn-studio-domain/src/main/java/com/svalyn/studio/domain/activity/repositories/IActivityEntryRepository.java @@ -35,6 +35,16 @@ */ @Repository public interface IActivityEntryRepository extends PagingAndSortingRepository, ListCrudRepository { + + @Query(value = """ + SELECT activityEntry.* + FROM activity activityEntry + ORDER BY activityEntry.created_on DESC + LIMIT :limit + OFFSET :offset + """) + List findAllVisibleByUserId(UUID userId, long offset, int limit); + @Query(value = """ SELECT activityEntry.* FROM activity activityEntry diff --git a/frontend/svalyn-studio-app/src/views/home/HomeView.tsx b/frontend/svalyn-studio-app/src/views/home/HomeView.tsx index bec9f5e..ea739d8 100644 --- a/frontend/svalyn-studio-app/src/views/home/HomeView.tsx +++ b/frontend/svalyn-studio-app/src/views/home/HomeView.tsx @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Stéphane Bégaudeau. + * Copyright (c) 2022, 2023 Stéphane Bégaudeau. * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * associated documentation files (the "Software"), to deal in the Software without restriction, @@ -17,50 +17,29 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { gql, useQuery } from '@apollo/client'; -import { useEffect, useState } from 'react'; -import { Navigate } from 'react-router-dom'; -import { GetOrganizationsData, GetOrganizationsVariables, HomeViewState } from './HomeView.types'; - -const getOrganizationsQuery = gql` - query getOrganizations { - viewer { - organizations { - edges { - node { - identifier - } - } - } - } - } -`; +import Box from '@mui/material/Box'; +import { Navbar } from '../../navbars/Navbar'; +import { HomeViewCenterPanel } from './HomeViewCenterPanel'; +import { HomeViewLeftPanel } from './HomeViewLeftPanel'; +import { HomeViewRightPanel } from './HomeViewRightPanel'; export const HomeView = () => { - const [state, setState] = useState({ - organizations: null, - }); - - const { loading, data } = useQuery(getOrganizationsQuery); - useEffect(() => { - if (!loading) { - if (data) { - const { - viewer: { organizations }, - } = data; - setState((prevState) => ({ ...prevState, organizations: organizations.edges.map((edge) => edge.node) })); - } - } - }, [loading, data]); - - if (state.organizations) { - if (state.organizations.length > 0) { - const organization = state.organizations[0]; - return ; - } else { - return ; - } - } - - return null; + return ( + + + + + + + + + ); }; diff --git a/frontend/svalyn-studio-app/src/views/home/HomeViewActivity.tsx b/frontend/svalyn-studio-app/src/views/home/HomeViewActivity.tsx new file mode 100644 index 0000000..6d5ec14 --- /dev/null +++ b/frontend/svalyn-studio-app/src/views/home/HomeViewActivity.tsx @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2023 Stéphane Bégaudeau. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import { gql, useQuery } from '@apollo/client'; +import Link from '@mui/material/Link'; +import Typography from '@mui/material/Typography'; +import { useEffect, useState } from 'react'; +import { ActivityTimeline } from '../../activity/ActivityTimeline'; +import { ErrorSnackbar } from '../../snackbar/ErrorSnackbar'; +import { + GetActivityData, + GetActivityVariables, + HomeViewActivityProps, + HomeViewActivityState, +} from './HomeViewActivity.types'; + +const getActivityQuery = gql` + query getActivity($page: Int!, $rowsPerPage: Int!) { + viewer { + activityEntries(page: $page, rowsPerPage: $rowsPerPage) { + edges { + node { + id + kind + title + description + createdOn + createdBy { + name + username + imageUrl + } + } + } + pageInfo { + hasNextPage + } + } + } + } +`; + +export const HomeViewActivity = ({}: HomeViewActivityProps) => { + const [state, setState] = useState({ + activityEntries: [], + page: 0, + rowsPerPage: 20, + message: null, + }); + + const variables: GetActivityVariables = { page: state.page, rowsPerPage: state.rowsPerPage }; + const { data, error } = useQuery(getActivityQuery, { variables }); + useEffect(() => { + if (data) { + const newActivityEntries = data.viewer.activityEntries.edges.map((edge) => edge.node); + setState((prevState) => ({ + ...prevState, + activityEntries: [...prevState.activityEntries, ...newActivityEntries], + })); + } + if (error) { + setState((prevState) => ({ ...prevState, message: error.message })); + } + }, [data, error]); + + const handleLoadMore = () => setState((prevState) => ({ ...prevState, page: prevState.page + 1 })); + + const handleCloseSnackbar = () => setState((prevState) => ({ ...prevState, message: null })); + + const hasNext = data?.viewer.activityEntries.pageInfo.hasNextPage ?? false; + return ( + <> +
+ Activity + + {hasNext ? Load more : null} +
+ + + ); +}; diff --git a/frontend/svalyn-studio-app/src/views/home/HomeViewActivity.types.ts b/frontend/svalyn-studio-app/src/views/home/HomeViewActivity.types.ts new file mode 100644 index 0000000..adaf389 --- /dev/null +++ b/frontend/svalyn-studio-app/src/views/home/HomeViewActivity.types.ts @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 Stéphane Bégaudeau. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +export interface HomeViewActivityProps {} + +export interface HomeViewActivityState { + activityEntries: ActivityEntry[]; + page: number; + rowsPerPage: number; + message: string | null; +} + +export interface GetActivityData { + viewer: Viewer; +} + +export interface Viewer { + activityEntries: ViewerActivityEntriesConnection; +} + +export interface ViewerActivityEntriesConnection { + edges: ViewerActivityEntriesEdge[]; + pageInfo: PageInfo; +} + +export interface PageInfo { + hasNextPage: boolean; +} + +export interface ViewerActivityEntriesEdge { + node: ActivityEntry; +} + +export interface ActivityEntry { + id: string; + kind: ActivityKind; + title: string; + description: string; + createdOn: string; + createdBy: ActivityEntryProfile; +} + +type ActivityKind = + | 'ACCOUNT_CREATED' + | 'ORGANIZATION_CREATED' + | 'PROJECT_CREATED' + | 'PROJECT_DELETED' + | 'CHANGE_PROPOSAL_CREATED' + | 'CHANGE_PROPOSAL_REVIEWED' + | 'CHANGE_PROPOSAL_INTEGRATED'; + +export interface ActivityEntryProfile { + name: string; + username: string; + imageUrl: string; +} + +export interface GetActivityVariables { + page: number; + rowsPerPage: number; +} diff --git a/frontend/svalyn-studio-app/src/views/home/HomeViewCenterPanel.tsx b/frontend/svalyn-studio-app/src/views/home/HomeViewCenterPanel.tsx new file mode 100644 index 0000000..3f22394 --- /dev/null +++ b/frontend/svalyn-studio-app/src/views/home/HomeViewCenterPanel.tsx @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023 Stéphane Bégaudeau. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import Box from '@mui/material/Box'; +import { HomeViewActivity } from './HomeViewActivity'; +import { HomeViewCenterPanelProps } from './HomeViewCenterPanel.types'; +import { HomeViewSearch } from './HomeViewSearch'; + +export const HomeViewCenterPanel = ({}: HomeViewCenterPanelProps) => { + return ( + <> + theme.spacing(10), + paddingX: (theme) => theme.spacing(4), + paddingTop: (theme) => theme.spacing(10), + paddingBottom: (theme) => theme.spacing(4), + }} + > + + + + + ); +}; diff --git a/frontend/svalyn-studio-app/src/views/home/HomeViewCenterPanel.types.ts b/frontend/svalyn-studio-app/src/views/home/HomeViewCenterPanel.types.ts new file mode 100644 index 0000000..91b6601 --- /dev/null +++ b/frontend/svalyn-studio-app/src/views/home/HomeViewCenterPanel.types.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2023 Stéphane Bégaudeau. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +export interface HomeViewCenterPanelProps {} diff --git a/frontend/svalyn-studio-app/src/views/home/HomeViewLeftPanel.tsx b/frontend/svalyn-studio-app/src/views/home/HomeViewLeftPanel.tsx new file mode 100644 index 0000000..4457f5d --- /dev/null +++ b/frontend/svalyn-studio-app/src/views/home/HomeViewLeftPanel.tsx @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2023 Stéphane Bégaudeau. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import { gql, useQuery } from '@apollo/client'; +import CorporateFareIcon from '@mui/icons-material/CorporateFare'; +import Box from '@mui/material/Box'; +import Button from '@mui/material/Button'; +import List from '@mui/material/List'; +import ListItem from '@mui/material/ListItem'; +import ListItemButton from '@mui/material/ListItemButton'; +import ListItemIcon from '@mui/material/ListItemIcon'; +import ListItemText from '@mui/material/ListItemText'; +import Paper from '@mui/material/Paper'; +import Typography from '@mui/material/Typography'; +import { useEffect, useState } from 'react'; +import { Link as RouterLink } from 'react-router-dom'; +import { ErrorSnackbar } from '../../snackbar/ErrorSnackbar'; +import { + GetOrganizationsData, + GetOrganizationsVariables, + HomeViewLeftPanelProps, + HomeViewLeftPanelState, +} from './HomeViewLeftPanel.types'; + +const getOrganizationsQuery = gql` + query getOrganizations { + viewer { + organizations { + edges { + node { + identifier + name + } + } + } + } + } +`; + +export const HomeViewLeftPanel = ({}: HomeViewLeftPanelProps) => { + const [state, setState] = useState({ + message: null, + }); + + const { data, error } = useQuery(getOrganizationsQuery); + useEffect(() => { + if (error) { + setState((prevState) => ({ ...prevState, message: error.message })); + } + }, [error]); + + const handleCloseSnackbar = () => setState((prevState) => ({ ...prevState, message: null })); + + const organizations = data?.viewer.organizations.edges.map((edge) => edge.node) ?? []; + return ( + <> + theme.spacing(1), + borderRight: (theme) => `1px solid ${theme.palette.divider}`, + }} + > + theme.spacing(2), + paddingBottom: (theme) => theme.spacing(1), + }} + > + Organizations + + + {data && organizations.length > 0 ? ( + + {organizations.map((organization) => { + return ( + + + + + + + + + ); + })} + + ) : ( + No organization found + )} + + + + ); +}; diff --git a/frontend/svalyn-studio-app/src/views/home/HomeView.types.ts b/frontend/svalyn-studio-app/src/views/home/HomeViewLeftPanel.types.ts similarity index 89% rename from frontend/svalyn-studio-app/src/views/home/HomeView.types.ts rename to frontend/svalyn-studio-app/src/views/home/HomeViewLeftPanel.types.ts index 3d6675d..2f9d0fe 100644 --- a/frontend/svalyn-studio-app/src/views/home/HomeView.types.ts +++ b/frontend/svalyn-studio-app/src/views/home/HomeViewLeftPanel.types.ts @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Stéphane Bégaudeau. + * Copyright (c) 2023 Stéphane Bégaudeau. * * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and * associated documentation files (the "Software"), to deal in the Software without restriction, @@ -17,12 +17,10 @@ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -export interface Organization { - identifier: string; -} +export interface HomeViewLeftPanelProps {} -export interface HomeViewState { - organizations: Organization[] | null; +export interface HomeViewLeftPanelState { + message: string | null; } export interface GetOrganizationsData { @@ -41,4 +39,9 @@ export interface ViewOrganizationsEdge { node: Organization; } +export interface Organization { + identifier: string; + name: string; +} + export interface GetOrganizationsVariables {} diff --git a/frontend/svalyn-studio-app/src/views/home/HomeViewRightPanel.tsx b/frontend/svalyn-studio-app/src/views/home/HomeViewRightPanel.tsx new file mode 100644 index 0000000..204b9b5 --- /dev/null +++ b/frontend/svalyn-studio-app/src/views/home/HomeViewRightPanel.tsx @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022 Stéphane Bégaudeau. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import Link from '@mui/material/Link'; +import Paper from '@mui/material/Paper'; +import Typography from '@mui/material/Typography'; +import { Link as RouterLink } from 'react-router-dom'; +import { HomeViewRightPanelProps } from './HomeViewRightPanel.types'; + +export const HomeViewRightPanel = ({}: HomeViewRightPanelProps) => { + return ( + <> + theme.spacing(2), + paddingY: (theme) => theme.spacing(1), + borderLeft: (theme) => `1px solid ${theme.palette.divider}`, + }} + > + + News + + + Release v2023.5.0 + + + Release v2023.3.0 + + + Release v2023.1.0 + + + Release v2022.11.0 + + + + ); +}; diff --git a/frontend/svalyn-studio-app/src/views/home/HomeViewRightPanel.types.ts b/frontend/svalyn-studio-app/src/views/home/HomeViewRightPanel.types.ts new file mode 100644 index 0000000..3c6eff2 --- /dev/null +++ b/frontend/svalyn-studio-app/src/views/home/HomeViewRightPanel.types.ts @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2022 Stéphane Bégaudeau. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +export interface HomeViewRightPanelProps {} diff --git a/frontend/svalyn-studio-app/src/views/home/HomeViewSearch.tsx b/frontend/svalyn-studio-app/src/views/home/HomeViewSearch.tsx new file mode 100644 index 0000000..4c453d1 --- /dev/null +++ b/frontend/svalyn-studio-app/src/views/home/HomeViewSearch.tsx @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023 Stéphane Bégaudeau. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +import SearchIcon from '@mui/icons-material/Search'; +import FormControl from '@mui/material/FormControl'; +import Input from '@mui/material/Input'; +import InputAdornment from '@mui/material/InputAdornment'; +import Paper from '@mui/material/Paper'; +import { useState } from 'react'; +import { HomeViewSearchState } from './HomeViewSearch.types'; + +export const HomeViewSearch = () => { + const [state, setState] = useState({ + query: '', + }); + + const handleQueryChange: React.ChangeEventHandler = (event) => { + const { + target: { value }, + } = event; + setState((prevState) => ({ ...prevState, query: value })); + }; + + return ( + theme.spacing(2) }}> + + + + + } + inputProps={{ + style: { + fontSize: '2rem', + }, + }} + /> + + + ); +}; diff --git a/frontend/svalyn-studio-app/src/views/home/HomeViewSearch.types.ts b/frontend/svalyn-studio-app/src/views/home/HomeViewSearch.types.ts new file mode 100644 index 0000000..9259215 --- /dev/null +++ b/frontend/svalyn-studio-app/src/views/home/HomeViewSearch.types.ts @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2023 Stéphane Bégaudeau. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and + * associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT + * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +export interface HomeViewSearchState { + query: string; +} diff --git a/frontend/svalyn-studio-app/src/views/profile/ProfileView.types.ts b/frontend/svalyn-studio-app/src/views/profile/ProfileView.types.ts index 60f2c60..f35b010 100644 --- a/frontend/svalyn-studio-app/src/views/profile/ProfileView.types.ts +++ b/frontend/svalyn-studio-app/src/views/profile/ProfileView.types.ts @@ -68,6 +68,7 @@ export interface ActivityEntryProfile { username: string; imageUrl: string; } + export interface GetViewerVariables { username: string; }