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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion apps/web/public/sw.js

Large diffs are not rendered by default.

60 changes: 60 additions & 0 deletions apps/web/src/api/format-error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { ErrorTypes } from "@/enums";
import i18next from "i18next";

const handleChainError = (strErr: string): [string | null, ErrorTypes] => {
if (/You may only post once every/.test(strErr)) {
return [i18next.t("chain-error.min-root-comment"), ErrorTypes.COMMON];
} else if (/Your current vote on this comment is identical/.test(strErr)) {
return [i18next.t("chain-error.identical-vote"), ErrorTypes.INFO];
} else if (/Must claim something/.test(strErr)) {
return [i18next.t("chain-error.must-claim"), ErrorTypes.INFO];
} else if (/Cannot claim that much VESTS/.test(strErr)) {
return [i18next.t("chain-error.must-claim"), ErrorTypes.INFO];
} else if (/Please wait to transact, or power up/.test(strErr)) {
return [
i18next.t("chain-error.insufficient-resource"),
ErrorTypes.INSUFFICIENT_RESOURCE_CREDITS
];
} else if (/Cannot delete a comment with net positive/.test(strErr)) {
return [i18next.t("chain-error.delete-comment-with-vote"), ErrorTypes.INFO];
} else if (/children == 0/.test(strErr)) {
return [i18next.t("chain-error.comment-children"), ErrorTypes.COMMON];
} else if (/comment_cashout/.test(strErr)) {
return [i18next.t("chain-error.comment-cashout"), ErrorTypes.COMMON];
} else if (/Votes evaluating for comment that is paid out is forbidden/.test(strErr)) {
return [i18next.t("chain-error.paid-out-post-forbidden"), ErrorTypes.COMMON];
} else if (/Missing Active Authority/.test(strErr)) {
return [i18next.t("chain-error.missing-authority"), ErrorTypes.INFO];
} else if (/Missing Owner Authority/.test(strErr)) {
return [i18next.t("chain-error.missing-owner-authority"), ErrorTypes.INFO];
}

return [null, ErrorTypes.COMMON];
};

export const formatError = (err: any): [string, ErrorTypes] => {
let [chainErr, type] = handleChainError(err.toString());
if (chainErr) {
return [chainErr, type];
}

if (err.error_description && typeof err.error_description === "string") {
let [chainErr, type] = handleChainError(err.error_description);
if (chainErr) {
return [chainErr, type];
}

return [err.error_description.substring(0, 80), ErrorTypes.COMMON];
}

if (err.message && typeof err.message === "string") {
let [chainErr, type] = handleChainError(err.message);
if (chainErr) {
return [chainErr, type];
}

return [err.message.substring(0, 80), ErrorTypes.COMMON];
}

return ["", ErrorTypes.COMMON];
};
41 changes: 0 additions & 41 deletions apps/web/src/api/mutations/account-claiming.ts

This file was deleted.

1 change: 0 additions & 1 deletion apps/web/src/api/mutations/bookmarks.ts

This file was deleted.

27 changes: 0 additions & 27 deletions apps/web/src/api/mutations/community-rewards-register.ts

This file was deleted.

12 changes: 8 additions & 4 deletions apps/web/src/api/mutations/community-set-user-role.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import { useMutation, useQuery, useQueryClient, UseQueryResult } from "@tanstack/react-query";
import { Community, CommunityTeam } from "@/entities";
import { formatError, setUserRole } from "@/api/operations";
import { formatError } from "@/api/format-error";
import { useActiveAccount } from "@/core/hooks/use-active-account";
import { clone } from "remeda";
import { QueryIdentifiers } from "@/core/react-query";
import { error } from "@/features/shared";
import { QueryKeys } from "@ecency/sdk";
import { getCommunityCache } from "@/core/caches";
import { useSetCommunityRoleMutation } from "@/api/sdk-mutations";

type TeamRow = [string, string, string]; // one member entry

Expand All @@ -19,17 +20,20 @@ export function useCommunitySetUserRole(communityName: string, onSuccess?: () =>
const { data: community } =
(useQuery(getCommunityCache(communityName)) as UseQueryResult<Community, Error>);

// Use SDK mutation for broadcasting
const { mutateAsync: setRoleSdk } = useSetCommunityRoleMutation(communityName);

return useMutation({
mutationKey: ["community-set-user-role", communityName],
mutationFn: async ({ user, role }: { user: string; role: string }) => {
await setUserRole(activeUser!.username, communityName, user, role);
await setRoleSdk({ account: user, role });
return { user, role };
},
onSuccess: ({ user, role }) => {
onSuccess?.();

queryClient.setQueryData<Community | undefined>(
[QueryIdentifiers.COMMUNITY, communityName],
QueryKeys.communities.single(communityName, ""),
(prev) => {
const base = (prev ?? community);
if (!base) return prev; // nothing cached yet
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/api/mutations/create-community.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useMutation } from "@tanstack/react-query";
import * as keychain from "@/utils/keychain";
import { error } from "@/features/shared";
import { formatError } from "@/api/operations";
import { formatError } from "@/api/format-error";
import { makeHsCode } from "@/utils";
import { EcencyConfigManager } from "@/config";
import { AccountCreateOperation, Authority, cryptoUtils, PrivateKey } from "@hiveio/dhive";
Expand Down
34 changes: 17 additions & 17 deletions apps/web/src/api/mutations/create-reply.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
// src/api/mutations/create-reply.ts
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { formatError } from "../operations";
import { formatError } from "../format-error";
import { Entry, FullAccount, MetaData, CommentOptions } from "@/entities";
import { tempEntry } from "@/utils";
import { QueryIdentifiers } from "@/core/react-query";
import { SortOrder } from "@/enums";
import { error, success } from "@/features/shared";
import { ErrorTypes } from "@/enums";
import * as ss from "@/utils/session-storage";
import i18next from "i18next";
import { getAccountRcQueryOptions } from "@ecency/sdk";
import { getAccountRcQueryOptions, addOptimisticDiscussionEntry, removeOptimisticDiscussionEntry } from "@ecency/sdk";
import { EcencyEntriesCacheManagement } from "@/core/caches";
import { useActiveAccount } from "@/core/hooks/use-active-account";
import { useCommentMutation } from "@/api/sdk-mutations";
Expand Down Expand Up @@ -132,14 +133,17 @@ export function useCreateReply(
success(i18next.t("comment.success"));
})
.catch((err) => {
// Blockchain failed - remove optimistic entry
// Blockchain failed - remove optimistic entry from web + SDK caches
queryClient.setQueryData<Entry[]>(
getDiscussionsCacheKey(),
(prev) =>
prev?.filter(
(r) => !(r.permlink === permlink && r.author === activeUser?.username)
) ?? []
);
removeOptimisticDiscussionEntry(
activeUser?.username ?? "", permlink, root.author, root.permlink, queryClient
);

// Notify parent component to restore text to input
if (onBlockchainError) {
Expand All @@ -148,18 +152,12 @@ export function useCreateReply(

// Keep draft in storage so user can retry by clicking Reply again
// Draft is still available from before, just don't delete it
const errorMessage = formatError(err);

// Check if it's an RC error
const errorString = JSON.stringify(err).toLowerCase();
const isRCError = errorString.includes("rc") ||
errorString.includes("resource credit") ||
errorString.includes("bandwidth");
const [errorMsg, errorType] = formatError(err);

if (isRCError) {
error(errorMessage[0], i18next.t("comment.rc-error-hint"));
if (errorType === ErrorTypes.INSUFFICIENT_RESOURCE_CREDITS) {
error(i18next.t("comment.rc-error-hint"), ErrorTypes.INSUFFICIENT_RESOURCE_CREDITS);
} else {
error(errorMessage[0], errorMessage[1] || i18next.t("comment.retry-hint"));
error(errorMsg || i18next.t("comment.retry-hint"), errorType);
}
});

Expand All @@ -170,9 +168,6 @@ export function useCreateReply(
onMutate: async ({ permlink, text }) => {
if (!activeUser || !account) return;

// Note: This creates a separate tempEntry from mutationFn (intentional)
// This entry gets is_optimistic = true for discussions cache
// mutationFn's entry is used for entry cache after blockchain confirms
const optimistic = tempEntry({
author: account,
permlink,
Expand All @@ -185,11 +180,13 @@ export function useCreateReply(
});
optimistic.is_optimistic = true;

// Add optimistic entry to cache immediately
// Add optimistic entry to web-specific discussions cache
queryClient.setQueryData<Entry[]>(
getDiscussionsCacheKey(),
(prev = []) => [optimistic, ...prev]
);
// Also add to SDK discussions cache (all sort orders)
addOptimisticDiscussionEntry(optimistic, root.author, root.permlink, queryClient);

return { optimistic, text };
},
Expand All @@ -213,6 +210,9 @@ export function useCreateReply(
!(r.permlink === optimistic?.permlink && r.author === optimistic?.author)
) ?? []
);
removeOptimisticDiscussionEntry(
optimistic.author, optimistic.permlink, root.author, root.permlink, queryClient
);
}

error(...formatError(err));
Expand Down
25 changes: 19 additions & 6 deletions apps/web/src/api/mutations/cross-post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ import { error, success } from "@/features/shared";
import { Entry } from "@/entities";
import { useActiveAccount } from "@/core/hooks/use-active-account";
import { makeCrossPostMessage } from "@/utils/cross-post";
import { makeApp, makeCommentOptions } from "@/utils";
import { makeApp } from "@/utils";
import pack from "../../../package.json";
import { comment, formatError } from "@/api/operations";
import { formatError } from "@/api/format-error";
import i18next from "i18next";
import { useCrossPostMutation } from "@/api/sdk-mutations";

export function useCrossPost(entry: Entry, onSuccess: () => void) {
const { activeUser } = useActiveAccount();
const sdkCrossPost = useCrossPostMutation();

return useMutation({
mutationKey: ["crossPost"],
Expand All @@ -38,10 +40,21 @@ export function useCrossPost(entry: Entry, onSuccess: () => void) {
original_permlink: entry.permlink
};

const options = makeCommentOptions(author, permlink, "dp")!;
options.allow_curation_rewards = false;

return comment(author, "", community.id, permlink, title, body, jsonMeta, options);
// Use SDK mutation with declined payout options
return sdkCrossPost.mutateAsync({
author,
permlink,
parentPermlink: community.id,
title,
body,
jsonMetadata: jsonMeta,
options: {
maxAcceptedPayout: "0.000 HBD",
percentHbd: 10000,
allowVotes: true,
allowCurationRewards: false
}
});
},
onSuccess: () => {
success(i18next.t("cross-post.published"));
Expand Down
63 changes: 0 additions & 63 deletions apps/web/src/api/mutations/delegate-vesting-shares.ts

This file was deleted.

Loading