diff --git a/apiserver/plane/db/migrations/0042_alter_analyticview_created_by_and_more.py b/apiserver/plane/db/migrations/0042_alter_analyticview_created_by_and_more.py index 62f08038c..01af46d20 100644 --- a/apiserver/plane/db/migrations/0042_alter_analyticview_created_by_and_more.py +++ b/apiserver/plane/db/migrations/0042_alter_analyticview_created_by_and_more.py @@ -32,19 +32,11 @@ class Migration(migrations.Migration): field=models.CharField(blank=True, max_length=255, null=True), ), migrations.RunPython(update_user_timezones), - migrations.AlterUniqueTogether( - name='issuevote', - unique_together=set(), - ), migrations.AlterField( model_name='issuevote', name='vote', field=models.IntegerField(choices=[(-1, 'DOWNVOTE'), (1, 'UPVOTE')], default=1), ), - migrations.AlterUniqueTogether( - name='issuevote', - unique_together={('issue', 'actor', 'vote')}, - ), migrations.CreateModel( name='ProjectPublicMember', fields=[ diff --git a/apiserver/plane/db/models/issue.py b/apiserver/plane/db/models/issue.py index 8f085b2a2..78e958380 100644 --- a/apiserver/plane/db/models/issue.py +++ b/apiserver/plane/db/models/issue.py @@ -481,7 +481,7 @@ class IssueVote(ProjectBaseModel): ) class Meta: - unique_together = ["issue", "actor", "vote"] + unique_together = ["issue", "actor",] verbose_name = "Issue Vote" verbose_name_plural = "Issue Votes" db_table = "issue_votes" diff --git a/apps/space/components/issues/board-views/block-state.tsx b/apps/space/components/issues/board-views/block-state.tsx index 6638566f9..16792c81b 100644 --- a/apps/space/components/issues/board-views/block-state.tsx +++ b/apps/space/components/issues/board-views/block-state.tsx @@ -1,5 +1,3 @@ -"use client"; - // constants import { issueGroupFilter } from "constants/data"; @@ -8,8 +6,8 @@ export const IssueBlockState = ({ state }: any) => { if (stateGroup === null) return <>; return ( -
-
+
+
{state?.name}
diff --git a/apps/space/components/issues/board-views/list/block.tsx b/apps/space/components/issues/board-views/list/block.tsx index a4b1ad2b8..7e6175ebb 100644 --- a/apps/space/components/issues/board-views/list/block.tsx +++ b/apps/space/components/issues/board-views/list/block.tsx @@ -14,6 +14,7 @@ import { useMobxStore } from "lib/mobx/store-provider"; import { IIssue } from "types/issue"; // store import { RootStore } from "store/root"; +import { IssueVotes } from "components/issues/peek-overview"; export const IssueListBlock: FC<{ issue: IIssue }> = observer((props) => { const { issue } = props; @@ -56,19 +57,6 @@ export const IssueListBlock: FC<{ issue: IIssue }> = observer((props) => {
- {projectStore.deploySettings?.votes && ( - <> - {/* upvotes */} -
- -
- {/* downotes */} -
- -
- - )} - {/* priority */} {issue?.priority && (
diff --git a/apps/space/components/issues/navbar/theme.tsx b/apps/space/components/issues/navbar/theme.tsx index faea53ba3..7efb561a4 100644 --- a/apps/space/components/issues/navbar/theme.tsx +++ b/apps/space/components/issues/navbar/theme.tsx @@ -1,25 +1,32 @@ -"use client"; - // next theme import { useTheme } from "next-themes"; // mobx react lite import { observer } from "mobx-react-lite"; +import { useEffect, useState } from "react"; export const NavbarTheme = observer(() => { + const [appTheme, setAppTheme] = useState("light"); + const { setTheme, theme } = useTheme(); const handleTheme = () => { setTheme(theme === "light" ? "dark" : "light"); }; + useEffect(() => { + if (!theme) return; + + setAppTheme(theme); + }, [theme]); + return ( ); }); diff --git a/apps/space/components/issues/peek-overview/comment-detail-card.tsx b/apps/space/components/issues/peek-overview/comment-detail-card.tsx index 7dee29aae..a43942f4c 100644 --- a/apps/space/components/issues/peek-overview/comment-detail-card.tsx +++ b/apps/space/components/issues/peek-overview/comment-detail-card.tsx @@ -61,8 +61,8 @@ export const CommentCard: React.FC = observer((props) => { ) : (
{comment.actor_detail.is_bot - ? comment.actor_detail.first_name.charAt(0) - : comment.actor_detail.display_name.charAt(0)} + ? comment?.actor_detail?.first_name?.charAt(0) + : comment?.actor_detail?.display_name?.charAt(0)}
)} diff --git a/apps/space/components/issues/peek-overview/header.tsx b/apps/space/components/issues/peek-overview/header.tsx index 7d2e76668..79de3978b 100644 --- a/apps/space/components/issues/peek-overview/header.tsx +++ b/apps/space/components/issues/peek-overview/header.tsx @@ -70,7 +70,7 @@ export const PeekOverviewHeader: React.FC = (props) => {
{issueDetailStore.peekMode === "side" && ( -
{(issueDetailStore.peekMode === "side" || issueDetailStore.peekMode === "modal") && (
-
diff --git a/apps/space/components/issues/peek-overview/issue-activity.tsx b/apps/space/components/issues/peek-overview/issue-activity.tsx index 47e9e4d0f..fde2fd878 100644 --- a/apps/space/components/issues/peek-overview/issue-activity.tsx +++ b/apps/space/components/issues/peek-overview/issue-activity.tsx @@ -47,7 +47,7 @@ export const PeekOverviewIssueActivity: React.FC = observer((props) => { )} ) : ( -
+

Sign in to add your comment diff --git a/apps/space/components/issues/peek-overview/issue-emoji-reactions.tsx b/apps/space/components/issues/peek-overview/issue-emoji-reactions.tsx index 1a81cecdf..3d2bfadac 100644 --- a/apps/space/components/issues/peek-overview/issue-emoji-reactions.tsx +++ b/apps/space/components/issues/peek-overview/issue-emoji-reactions.tsx @@ -24,9 +24,7 @@ export const IssueEmojiReactions: React.FC = observer(() => { if (!workspace_slug || !project_slug || !issueId) return; const userReaction = reactions?.find((r) => r.actor_detail.id === user?.id && r.reaction === reactionHex); if (userReaction) return; - issueDetailsStore.addIssueReaction(workspace_slug.toString(), project_slug.toString(), issueId, { - reaction: reactionHex, - }); + issueDetailsStore.addIssueReaction(workspace_slug.toString(), project_slug.toString(), issueId, reactionHex); }; const handleReactionClick = (reactionHex: string) => { @@ -57,6 +55,7 @@ export const IssueEmojiReactions: React.FC = observer(() => { if (reactions.length > 0) return ( {reactions @@ -74,7 +73,6 @@ export const IssueEmojiReactions: React.FC = observer(() => { handleReactionClick(reaction); }); }} - key={reaction} className={`flex items-center gap-1 text-custom-text-100 text-sm h-full px-2 py-1 rounded-md ${ reactions?.some((r) => r.actor_detail.id === user?.id && r.reaction === reaction) ? "bg-custom-primary-100/10" diff --git a/apps/space/store/issue_details.ts b/apps/space/store/issue_details.ts index 68f9af1ca..10679cf17 100644 --- a/apps/space/store/issue_details.ts +++ b/apps/space/store/issue_details.ts @@ -1,9 +1,10 @@ import { makeObservable, observable, action, runInAction } from "mobx"; +import { v4 as uuidv4 } from "uuid"; // store import { RootStore } from "./root"; // services import IssueService from "services/issue.service"; -import { IIssue } from "types/issue"; +import { IIssue, IVote } from "types/issue"; export type IPeekMode = "side" | "modal" | "full"; @@ -32,8 +33,8 @@ export interface IIssueDetailStore { ) => Promise; deleteIssueComment: (workspaceId: string, projectId: string, issueId: string, comment_id: string) => void; // issue reactions - addIssueReaction: (workspaceId: string, projectId: string, issueId: string, data: any) => void; - removeIssueReaction: (workspaceId: string, projectId: string, issueId: string, reactionId: string) => void; + addIssueReaction: (workspaceId: string, projectId: string, issueId: string, reactionHex: string) => void; + removeIssueReaction: (workspaceId: string, projectId: string, issueId: string, reactionHex: string) => void; // issue votes addIssueVote: (workspaceId: string, projectId: string, issueId: string, data: { vote: 1 | -1 }) => Promise; removeIssueVote: (workspaceId: string, projectId: string, issueId: string) => Promise; @@ -88,7 +89,7 @@ class IssueDetailStore implements IssueDetailStore { this.details = { ...this.details, [issueId]: { - ...issueDetails, + ...(this.details[issueId] ?? issueDetails), comments: commentsResponse, }, }; @@ -174,84 +175,144 @@ class IssueDetailStore implements IssueDetailStore { } }; - addIssueReaction = async (workspaceSlug: string, projectId: string, issueId: string, data: any) => { + addIssueReaction = async (workspaceSlug: string, projectId: string, issueId: string, reactionHex: string) => { try { - const issueVoteResponse = await this.issueService.createIssueReaction(workspaceSlug, projectId, issueId, data); + runInAction(() => { + this.details = { + ...this.details, + [issueId]: { + ...this.details[issueId], + reactions: [ + ...this.details[issueId].reactions, + { + id: uuidv4(), + issue: issueId, + reaction: reactionHex, + actor_detail: this.rootStore.user.currentActor, + }, + ], + }, + }; + }); - if (issueVoteResponse) { - runInAction(() => { - this.details = { - ...this.details, - [issueId]: { - ...this.details[issueId], - reactions: [...this.details[issueId].reactions, issueVoteResponse], - }, - }; - }); - } + await this.issueService.createIssueReaction(workspaceSlug, projectId, issueId, { + reaction: reactionHex, + }); } catch (error) { console.log("Failed to add issue vote"); + const issueReactions = await this.issueService.getIssueReactions(workspaceSlug, projectId, issueId); + runInAction(() => { + this.details = { + ...this.details, + [issueId]: { + ...this.details[issueId], + reactions: issueReactions, + }, + }; + }); } }; - removeIssueReaction = async (workspaceSlug: string, projectId: string, issueId: string, reactionId: string) => { + removeIssueReaction = async (workspaceSlug: string, projectId: string, issueId: string, reactionHex: string) => { try { - await this.issueService.deleteIssueReaction(workspaceSlug, projectId, issueId, reactionId); - const reactions = await this.issueService.getIssueReactions(workspaceSlug, projectId, issueId); + const newReactions = this.details[issueId].reactions.filter( + (_r) => !(_r.reaction === reactionHex && _r.actor_detail.id === this.rootStore.user.currentUser?.id) + ); - if (reactions) { - runInAction(() => { - this.details = { - ...this.details, - [issueId]: { - ...this.details[issueId], - reactions: reactions, - }, - }; - }); - } + runInAction(() => { + this.details = { + ...this.details, + [issueId]: { + ...this.details[issueId], + reactions: newReactions, + }, + }; + }); + + await this.issueService.deleteIssueReaction(workspaceSlug, projectId, issueId, reactionHex); } catch (error) { console.log("Failed to remove issue reaction"); + const reactions = await this.issueService.getIssueReactions(workspaceSlug, projectId, issueId); + runInAction(() => { + this.details = { + ...this.details, + [issueId]: { + ...this.details[issueId], + reactions: reactions, + }, + }; + }); } }; addIssueVote = async (workspaceSlug: string, projectId: string, issueId: string, data: { vote: 1 | -1 }) => { - try { - const issueVoteResponse = await this.issueService.createIssueVote(workspaceSlug, projectId, issueId, data); - const issueDetails = await this.issueService.getIssueById(workspaceSlug, projectId, issueId); + const newVote: IVote = { + actor: this.rootStore.user.currentUser?.id ?? "", + actor_detail: this.rootStore.user.currentActor, + issue: issueId, + project: projectId, + workspace: workspaceSlug, + vote: data.vote, + }; - if (issueVoteResponse) { - runInAction(() => { - this.details = { - ...this.details, - [issueId]: { - ...issueDetails, - }, - }; - }); - } + const filteredVotes = this.details[issueId].votes.filter((v) => v.actor !== this.rootStore.user.currentUser?.id); + + try { + runInAction(() => { + this.details = { + ...this.details, + [issueId]: { + ...this.details[issueId], + votes: [...filteredVotes, newVote], + }, + }; + }); + + await this.issueService.createIssueVote(workspaceSlug, projectId, issueId, data); } catch (error) { console.log("Failed to add issue vote"); + const issueVotes = await this.issueService.getIssueVotes(workspaceSlug, projectId, issueId); + + runInAction(() => { + this.details = { + ...this.details, + [issueId]: { + ...this.details[issueId], + votes: issueVotes, + }, + }; + }); } }; removeIssueVote = async (workspaceSlug: string, projectId: string, issueId: string) => { - try { - await this.issueService.deleteIssueVote(workspaceSlug, projectId, issueId); - const issueDetails = await this.issueService.getIssueById(workspaceSlug, projectId, issueId); + const newVotes = this.details[issueId].votes.filter((v) => v.actor !== this.rootStore.user.currentUser?.id); - if (issueDetails) { - runInAction(() => { - this.details = { - ...this.details, - [issueId]: { - ...issueDetails, - }, - }; - }); - } + try { + runInAction(() => { + this.details = { + ...this.details, + [issueId]: { + ...this.details[issueId], + votes: newVotes, + }, + }; + }); + + await this.issueService.deleteIssueVote(workspaceSlug, projectId, issueId); } catch (error) { console.log("Failed to remove issue vote"); + const issueVotes = await this.issueService.getIssueVotes(workspaceSlug, projectId, issueId); + + runInAction(() => { + this.details = { + ...this.details, + [issueId]: { + ...this.details[issueId], + votes: issueVotes, + }, + }; + }); } }; } diff --git a/apps/space/store/issue_legacy.ts b/apps/space/store/issue_legacy.ts deleted file mode 100644 index a2cc2e306..000000000 --- a/apps/space/store/issue_legacy.ts +++ /dev/null @@ -1,566 +0,0 @@ -// mobx -import { observable, action, computed, makeObservable, runInAction, reaction } from "mobx"; -// service -import IssueService from "services/issue.service"; -// types -import { IssueDetailType, TIssueBoardKeys, IIssueLabel, IIssueState, IIssue } from "types/issue"; - -export interface IIssueStore { - currentIssueBoardView: TIssueBoardKeys | null; - loader: boolean; - error: any | null; - states: IIssueState[] | null; - labels: IIssueLabel[] | null; - issues: IIssue[] | null; - issue_detail: IssueDetailType; - userSelectedStates: string[]; - userSelectedLabels: string[]; - userSelectedPriorities: string[]; - activePeekOverviewIssueId: string | null; - getCountOfIssuesByState: (state: string) => number; - getFilteredIssuesByState: (state: string) => IIssue[]; - getUserSelectedFilter: (key: "state" | "priority" | "label", value: string) => boolean; - checkIfFilterExistsForKey: (key: "state" | "priority" | "label") => boolean; - clearUserSelectedFilter: (key: "state" | "priority" | "label" | "all") => void; - getIfFiltersIsEmpty: () => boolean; - getURLDefinition: ( - workspaceSlug: string, - projectId: string, - action?: { - key: "state" | "priority" | "label" | "all"; - value?: string; - removeAll?: boolean; - } - ) => string; - setActivePeekOverviewIssueId: (value: any) => void; - setCurrentIssueBoardView: (view: TIssueBoardKeys) => void; - fetchPublicIssues: (workspaceSlug: string, projectId: string, params: any) => Promise; - getIssueByIdAsync: (workspaceSlug: string, projectId: string, issueId: string) => Promise; -} - -class IssueLegacyStore { - currentIssueBoardView: TIssueBoardKeys | null = null; - - loader: boolean = false; - error: any | null = null; - - states: IIssueState[] | null = null; - labels: IIssueLabel[] | null = null; - issues: IIssue[] | null = null; - - issue_detail: IssueDetailType = {}; - - activePeekOverviewIssueId: string | null = null; - - userSelectedStates: string[] = []; - userSelectedLabels: string[] = []; - userSelectedPriorities: string[] = []; - // root store - rootStore; - // service - issueService; - - constructor(_rootStore: any) { - makeObservable(this, { - // observable - currentIssueBoardView: observable, - - loader: observable, - error: observable, - - states: observable.ref, - labels: observable.ref, - issues: observable.ref, - issue_detail: observable.ref, - - activePeekOverviewIssueId: observable.ref, - - userSelectedStates: observable.ref, - userSelectedLabels: observable.ref, - userSelectedPriorities: observable.ref, - // action - setCurrentIssueBoardView: action, - fetchPublicIssues: action, - // computed - }); - - this.rootStore = _rootStore; - this.issueService = new IssueService(); - } - - // computed - getCountOfIssuesByState(state_id: string): number { - return this.issues?.filter((issue) => issue.state == state_id).length || 0; - } - - getFilteredIssuesByState(state_id: string): IIssue[] | [] { - return this.issues?.filter((issue) => issue.state == state_id) || []; - } - - setActivePeekOverviewIssueId = (issueId: string | null) => (this.activePeekOverviewIssueId = issueId); - - /** - * - * @param key Is the key of the filter, i.e. state, label, priority - * @param value Is the value of the filter, i.e. state_id, label_id, priority - * @returns boolean - */ - - getUserSelectedFilter(key: "state" | "priority" | "label", value: string): boolean { - if (key == "state") { - return this.userSelectedStates.includes(value); - } else if (key == "label") { - return this.userSelectedLabels.includes(value); - } else if (key == "priority") { - return this.userSelectedPriorities.includes(value); - } else { - return false; - } - } - - checkIfFilterExistsForKey: (key: "state" | "priority" | "label") => boolean = (key) => { - if (key == "state") { - return this.userSelectedStates.length > 0; - } else if (key == "label") { - return this.userSelectedLabels.length > 0; - } else if (key == "priority") { - return this.userSelectedPriorities.length > 0; - } else { - return false; - } - }; - - clearUserSelectedFilter(key: "state" | "priority" | "label" | "all") { - if (key == "state") { - this.userSelectedStates = []; - } else if (key == "label") { - this.userSelectedLabels = []; - } else if (key == "priority") { - this.userSelectedPriorities = []; - } else if (key == "all") { - this.userSelectedStates = []; - this.userSelectedLabels = []; - this.userSelectedPriorities = []; - } - } - - getIfFiltersIsEmpty: () => boolean = () => - this.userSelectedStates.length === 0 && - this.userSelectedLabels.length === 0 && - this.userSelectedPriorities.length === 0; - - getURLDefinition = ( - workspaceSlug: string, - projectId: string, - action?: { - key: "state" | "priority" | "label" | "all"; - value?: string; - removeAll?: boolean; - } - ) => { - let url = `/${workspaceSlug}/${projectId}?board=${this.currentIssueBoardView}`; - - if (action) { - if (action.key === "state") - this.userSelectedStates = action.removeAll - ? [] - : [...this.userSelectedStates].filter((state) => state !== action.value); - if (action.key === "label") - this.userSelectedLabels = action.removeAll - ? [] - : [...this.userSelectedLabels].filter((label) => label !== action.value); - if (action.key === "priority") - this.userSelectedPriorities = action.removeAll - ? [] - : [...this.userSelectedPriorities].filter((priority) => priority !== action.value); - if (action.key === "all") { - this.userSelectedStates = []; - this.userSelectedLabels = []; - this.userSelectedPriorities = []; - } - } - - if (this.checkIfFilterExistsForKey("state")) { - url += `&states=${this.userSelectedStates.join(",")}`; - } - if (this.checkIfFilterExistsForKey("label")) { - url += `&labels=${this.userSelectedLabels.join(",")}`; - } - if (this.checkIfFilterExistsForKey("priority")) { - url += `&priorities=${this.userSelectedPriorities.join(",")}`; - } - - return url; - }; - - // action - setCurrentIssueBoardView = async (view: TIssueBoardKeys) => { - this.currentIssueBoardView = view; - }; - - fetchPublicIssues = async (workspaceSlug: string, projectId: string, params: any) => { - try { - this.loader = true; - this.error = null; - - const response = await this.issueService.getPublicIssues(workspaceSlug, projectId, params); - - if (response) { - const _states: IIssueState[] = [...response?.states]; - const _labels: IIssueLabel[] = [...response?.labels]; - const _issues: IIssue[] = [...response?.issues]; - runInAction(() => { - this.states = _states; - this.labels = _labels; - this.issues = _issues; - this.loader = false; - }); - return response; - } - } catch (error) { - this.loader = false; - this.error = error; - return error; - } - }; - - getIssueByIdAsync = async (workspaceSlug: string, projectId: string, issueId: string): Promise => { - try { - const response = this.issues?.find((issue) => issue.id === issueId); - - if (response) { - const _issue_detail = { - ...this.issue_detail, - [issueId]: { - issue: response, - comments: [], - reactions: [], - votes: [], - }, - }; - runInAction(() => { - this.issue_detail = _issue_detail; - }); - - this.getIssueReactionsAsync(workspaceSlug, projectId, issueId); - this.getIssueVotesAsync(workspaceSlug, projectId, issueId); - this.getIssueCommentsAsync(workspaceSlug, projectId, issueId); - } - - return this.issue_detail[issueId] as any; - } catch (error) { - this.loader = false; - this.error = error; - throw error; - } - }; - - getIssueVotesAsync = async (workspaceSlug: string, projectId: string, issueId: string) => { - try { - const response = await this.issueService.getIssueVotes(workspaceSlug, projectId, issueId); - - if (response) { - const _issue_detail = { - ...this.issue_detail, - [issueId]: { - ...this.issue_detail[issueId], - votes: response, - }, - }; - runInAction(() => { - this.issue_detail = _issue_detail; - }); - } - - return response; - } catch (error) { - this.loader = false; - this.error = error; - throw error; - } - }; - - createIssueVoteAsync = async ( - workspaceSlug: string, - projectId: string, - issueId: string, - data: { - vote: 1 | -1; - } - ) => { - try { - const response = await this.issueService.createIssueVote(workspaceSlug, projectId, issueId, data); - - if (response) { - const _issue_detail = { - ...this.issue_detail, - [issueId]: { - ...this.issue_detail[issueId], - votes: [ - ...{ ...this.issue_detail }[issueId].votes.filter( - (vote) => vote.actor !== this.rootStore?.user?.currentUser?.id - ), - response, - ], - }, - }; - runInAction(() => { - this.issue_detail = _issue_detail; - }); - } - - return response; - } catch (error) { - this.loader = false; - this.error = error; - throw error; - } - }; - - deleteIssueVoteAsync = async (workspaceSlug: string, projectId: string, issueId: string) => { - try { - const _votes = (this.issue_detail[issueId].votes = this.issue_detail[issueId].votes.filter( - (vote) => vote.actor !== this.rootStore?.user?.user?.id - )); - - runInAction(() => { - this.issue_detail[issueId].votes = _votes; - }); - - const response = await this.issueService.deleteIssueVote(workspaceSlug, projectId, issueId); - - const votesAfterCall = await this.issueService.getIssueVotes(workspaceSlug, projectId, issueId); - - if (votesAfterCall) - runInAction(() => { - this.issue_detail[issueId].votes = votesAfterCall; - }); - - return response; - } catch (error) { - this.loader = false; - this.error = error; - throw error; - } - }; - - getIssueReactionsAsync = async (workspaceSlug: string, projectId: string, issueId: string) => { - try { - const response = await this.issueService.getIssueReactions(workspaceSlug, projectId, issueId); - - if (response) { - const _issue_detail = { - ...this.issue_detail, - [issueId]: { - ...this.issue_detail[issueId], - reactions: response, - }, - }; - runInAction(() => { - this.issue_detail = _issue_detail; - }); - } - - return response; - } catch (error) { - this.loader = false; - this.error = error; - throw error; - } - }; - - createIssueReactionAsync = async (workspaceSlug: string, projectId: string, issueId: string, data: any) => { - try { - const response = await this.issueService.createIssueReaction(workspaceSlug, projectId, issueId, data); - - if (response) { - const _issue_detail = { - ...this.issue_detail, - [issueId]: { - ...this.issue_detail[issueId], - reactions: [...this.issue_detail[issueId].reactions, response], - }, - }; - runInAction(() => { - this.issue_detail = _issue_detail; - }); - } - - return response; - } catch (error) { - this.loader = false; - this.error = error; - throw error; - } - }; - - deleteIssueReactionAsync = async (workspaceSlug: string, projectId: string, issueId: string, reactionHex: string) => { - try { - const newReactionsList = this.issue_detail[issueId].reactions.filter( - (reaction) => reaction.reaction !== reactionHex - ); - - const _issue_detail = { - ...this.issue_detail, - [issueId]: { - ...this.issue_detail[issueId], - reactions: newReactionsList, - }, - }; - - runInAction(() => { - this.issue_detail = _issue_detail; - }); - - const response = await this.issueService.deleteIssueReaction(workspaceSlug, projectId, issueId, reactionHex); - - const reactionsAfterCall = await this.issueService.getIssueReactions(workspaceSlug, projectId, issueId); - - if (reactionsAfterCall) { - const _issue_detail = { - ...this.issue_detail, - [issueId]: { - ...this.issue_detail[issueId], - reactions: reactionsAfterCall, - }, - }; - runInAction(() => { - this.issue_detail = _issue_detail; - }); - } - - return response; - } catch (error) { - this.loader = false; - this.error = error; - throw error; - } - }; - - getIssueCommentsAsync = async (workspaceSlug: string, projectId: string, issueId: string) => { - try { - const response = await this.issueService.getIssueComments(workspaceSlug, projectId, issueId); - - if (response) { - const _issue_detail = { - ...this.issue_detail, - [issueId]: { - ...this.issue_detail[issueId], - comments: response, - }, - }; - runInAction(() => { - this.issue_detail = _issue_detail; - }); - } - - return response; - } catch (error) { - this.loader = false; - this.error = error; - throw error; - } - }; - - createIssueCommentAsync = async (workspaceSlug: string, projectId: string, issueId: string, data: any) => { - try { - const response = await this.issueService.createIssueComment(workspaceSlug, projectId, issueId, data); - - if (response) { - const _issue_detail = { - ...this.issue_detail, - [issueId]: { - ...this.issue_detail[issueId], - comments: [...this.issue_detail[issueId].comments, response], - }, - }; - runInAction(() => { - this.issue_detail = _issue_detail; - }); - } - - return response; - } catch (error) { - this.loader = false; - this.error = error; - throw error; - } - }; - - updateIssueCommentAsync = async ( - workspaceSlug: string, - projectId: string, - issueId: string, - commentId: string, - data: any - ) => { - try { - const response = await this.issueService.updateIssueComment(workspaceSlug, projectId, issueId, commentId, data); - - if (response) { - const _issue_detail = { - ...this.issue_detail, - [issueId]: { - ...this.issue_detail[issueId], - comments: [ - ...this.issue_detail[issueId].comments.filter((comment) => comment.id !== response.id), - response, - ], - }, - }; - runInAction(() => { - this.issue_detail = _issue_detail; - }); - } - - return response; - } catch (error) { - this.loader = false; - this.error = error; - throw error; - } - }; - - deleteIssueCommentAsync = async (workspaceSlug: string, projectId: string, issueId: string, commentId: string) => { - try { - const newCommentsList = this.issue_detail[issueId].comments.filter((comment) => comment.id !== commentId); - - const _issue_detail = { - ...this.issue_detail, - [issueId]: { - ...this.issue_detail[issueId], - comments: newCommentsList, - }, - }; - - runInAction(() => { - this.issue_detail = _issue_detail; - }); - - const response = await this.issueService.deleteIssueComment(workspaceSlug, projectId, issueId, commentId); - - const commentsAfterCall = await this.issueService.getIssueComments(workspaceSlug, projectId, issueId); - - if (commentsAfterCall) { - const _issue_detail = { - ...this.issue_detail, - [issueId]: { - ...this.issue_detail[issueId], - comments: commentsAfterCall, - }, - }; - runInAction(() => { - this.issue_detail = _issue_detail; - }); - } - - return response; - } catch (error) { - this.loader = false; - this.error = error; - throw error; - } - }; -} - -export default IssueLegacyStore; diff --git a/apps/space/store/user.ts b/apps/space/store/user.ts index b1a87d133..8d34b0bdc 100644 --- a/apps/space/store/user.ts +++ b/apps/space/store/user.ts @@ -2,14 +2,18 @@ import { observable, action, computed, makeObservable, runInAction } from "mobx"; // service import UserService from "services/user.service"; +import { ActorDetail } from "types/issue"; +// types +import { IUser } from "types/user"; export interface IUserStore { currentUser: any | null; fetchCurrentUser: () => void; + currentActor: () => any; } class UserStore implements IUserStore { - currentUser: any | null = null; + currentUser: IUser | null = null; // root store rootStore; // service @@ -22,6 +26,7 @@ class UserStore implements IUserStore { // actions setCurrentUser: action, // computed + currentActor: computed, }); this.rootStore = _rootStore; this.userService = new UserService(); @@ -33,6 +38,17 @@ class UserStore implements IUserStore { }); }; + get currentActor(): any { + return { + avatar: this.currentUser?.avatar, + display_name: this.currentUser?.display_name, + first_name: this.currentUser?.first_name, + id: this.currentUser?.id, + is_bot: false, + last_name: this.currentUser?.last_name, + }; + } + /** * * @param callback diff --git a/apps/space/types/issue.ts b/apps/space/types/issue.ts index 323df995c..754da6ae3 100644 --- a/apps/space/types/issue.ts +++ b/apps/space/types/issue.ts @@ -42,14 +42,7 @@ export interface IIssue { state: string; state_detail: any; target_date: any; - votes: { - issue: string; - vote: -1 | 1; - workspace: string; - project: string; - actor: string; - actor_detail: ActorDetail; - }[]; + votes: IVote[]; } export interface IIssueState { @@ -65,6 +58,15 @@ export interface IIssueLabel { color: string; } +export interface IVote { + issue: string; + vote: -1 | 1; + workspace: string; + project: string; + actor: string; + actor_detail: ActorDetail; +} + export interface Comment { id: string; actor_detail: ActorDetail; @@ -95,12 +97,12 @@ export interface IIssueReaction { } export interface ActorDetail { - avatar: string; - display_name: string; - first_name: string; - id: string; - is_bot: boolean; - last_name: string; + avatar?: string; + display_name?: string; + first_name?: string; + id?: string; + is_bot?: boolean; + last_name?: string; } export interface IssueDetail { diff --git a/apps/space/types/user.ts b/apps/space/types/user.ts index 45b3f3b6e..8c6d5f681 100644 --- a/apps/space/types/user.ts +++ b/apps/space/types/user.ts @@ -1,3 +1,23 @@ export interface IUser { + avatar: string; + cover_image: string | null; + created_at: Date; + created_location: string; + date_joined: Date; + email: string; + display_name: string; first_name: string; + id: string; + is_email_verified: boolean; + is_onboarded: boolean; + is_tour_completed: boolean; + last_location: string; + last_login: Date; + last_name: string; + mobile_number: string; + role: string; + token: string; + updated_at: Date; + username: string; + user_timezone: string; }