Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor registration / profile update flows #327

Draft
wants to merge 37 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
0e5c65f
taking out validation from effects file
Jikugodwill Jan 15, 2025
7c6d45e
updated design to use react-hook-form instead
Jikugodwill Jan 15, 2025
2efe5c7
Added more refinement to the hook
Jikugodwill Jan 16, 2025
6e367f6
taking out redux code and replacing with rhf
Jikugodwill Jan 16, 2025
3469a04
Reverting back some old code for testing
Jikugodwill Jan 16, 2025
977cafd
Added param to hook
Jikugodwill Jan 16, 2025
7704dd5
more rhf updates
Jikugodwill Jan 16, 2025
02407c0
commented errors out
Jikugodwill Jan 16, 2025
fb17162
Merge branch 'main' of https://github.com/PotLock/potlock-nextjs-app …
Jikugodwill Jan 20, 2025
b11b488
updated for addFundingSources schema object
Jikugodwill Jan 20, 2025
4056429
Updated components to completely use react-hook-form
Jikugodwill Jan 21, 2025
dcfdb28
Removed unused imports from the hook and reverted saveProject()
Jikugodwill Jan 21, 2025
eeaace8
reverted saveProject() in effects
Jikugodwill Jan 21, 2025
995ad3e
updated input value to the more reactive "values"
Jikugodwill Jan 21, 2025
3d0acf6
updating to the more recent useSession
Jikugodwill Jan 21, 2025
aec392f
updated hook
Jikugodwill Jan 21, 2025
2eb8ba4
removed unused code and imports
Jikugodwill Jan 21, 2025
4fc4a76
added project isEdit check
Jikugodwill Jan 21, 2025
7f0d02a
wip
carina-akaia Jan 22, 2025
e90a2ae
wip
carina-akaia Jan 22, 2025
9a5a5fa
wip
carina-akaia Jan 22, 2025
e715b2e
wip
carina-akaia Jan 22, 2025
fd24c6b
Merge branch 'main' of https://github.com/PotLock/potlock-nextjs-app …
carina-akaia Jan 22, 2025
45f4ce0
wip
carina-akaia Jan 22, 2025
8e19d89
wip
carina-akaia Jan 23, 2025
2ebc8e6
wip
carina-akaia Jan 23, 2025
9f182a8
wip
carina-akaia Jan 23, 2025
0519f57
wip
carina-akaia Jan 23, 2025
80d3aad
wip
carina-akaia Jan 23, 2025
1885953
wip
carina-akaia Jan 23, 2025
71d85e9
wip
carina-akaia Jan 23, 2025
8e19ec4
wip
carina-akaia Jan 23, 2025
7f1086e
wip
carina-akaia Jan 23, 2025
66c9e10
wip
carina-akaia Jan 23, 2025
097e6c2
wip
carina-akaia Jan 23, 2025
c93b188
wip
carina-akaia Jan 23, 2025
f2930f5
Fix: remove reference to a non-existent model
carina-akaia Jan 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"errorLens.warningGutterIconColor": "#ff942f",
"cSpell.words": [
"amichaeltest",
"Aptos",
"Attributify",
"bitget",
"builddao",
Expand All @@ -58,14 +59,17 @@
"datetime",
"defi",
"dontcare",
"Elrond",
"fastnear",
"foodbank",
"formkit",
"graylisted",
"hookform",
"Injective",
"intear",
"Jikugodwill",
"kubb",
"Linea",
"linktree",
"METAPOOL",
"mpdao",
Expand All @@ -78,6 +82,7 @@
"openapi",
"overscan",
"partialize",
"Polkadot",
"potfactory",
"POTLOCK",
"precommit",
Expand All @@ -89,6 +94,7 @@
"sessionid",
"shadcn",
"socialdb",
"Solana",
"SOURCECODE",
"stnear",
"svgr",
Expand Down
14 changes: 8 additions & 6 deletions src/common/api/indexer/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,16 @@ export const useAccountActivePots = ({
* https://test-dev.potlock.io/api/schema/swagger-ui/#/v1/v1_accounts_list_registrations_retrieve
*/
export const useAccountListRegistrations = ({
enabled = true,
accountId,
...params
}: Partial<ByAccountId> & generatedClient.V1AccountsListRegistrationsRetrieveParams) => {
const queryResult = generatedClient.useV1AccountsListRegistrationsRetrieve(
accountId ?? "noop",
params,
{ ...INDEXER_CLIENT_CONFIG, swr: { enabled: Boolean(accountId) } },
);
}: ByAccountId &
generatedClient.V1AccountsListRegistrationsRetrieveParams &
ConditionalActivation) => {
const queryResult = generatedClient.useV1AccountsListRegistrationsRetrieve(accountId, params, {
...INDEXER_CLIENT_CONFIG,
swr: { enabled },
});

return { ...queryResult, data: queryResult.data?.data };
};
Expand Down
2 changes: 2 additions & 0 deletions src/common/api/indexer/internal/client.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1128,6 +1128,8 @@ export interface ListRegistration {
admin_notes?: string | null;
/** Registration id. */
readonly id: number;
/** List registered. */
readonly list_id: number;
registered_by: Account;
registrant: Account;
/**
Expand Down
42 changes: 42 additions & 0 deletions src/common/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,48 @@ export const APP_METADATA: Metadata & {
},
};

export const CHAIN_OPTIONS: Record<string, { isEVM: boolean }> = {
NEAR: { isEVM: false },
Solana: { isEVM: false },
Ethereum: { isEVM: true },
Polygon: { isEVM: true },
Avalanche: { isEVM: true },
Optimism: { isEVM: true },
Arbitrum: { isEVM: true },
BNB: { isEVM: true },
Sui: { isEVM: false },
Aptos: { isEVM: false },
Polkadot: { isEVM: false },
Stellar: { isEVM: false },

// Note: ZkSync aims for EVM compatibility but might not fully be considered as traditional EVM
// at the time of writing.
ZkSync: { isEVM: false },

Celo: { isEVM: true },
Aurora: { isEVM: true },
Injective: { isEVM: true },
Base: { isEVM: false },

// Listed twice in the original list; included once here.
Manta: { isEVM: false },

Fantom: { isEVM: true },
ZkEVM: { isEVM: true },
Flow: { isEVM: false },
Tron: { isEVM: true },

// Formerly known as Elrond, not traditionally EVM but has some level of compatibility.
MultiverseX: { isEVM: false },

// Assuming EVM compatibility based on the context of ZkEVM.
Scroll: { isEVM: true },

// Assuming non-EVM due to lack of information.
Linea: { isEVM: true },
Metis: { isEVM: true },
};

export const TOTAL_FEE_BASIS_POINTS = 10_000;
export const TOP_LEVEL_ROOT_ACCOUNT_ID = NETWORK === "mainnet" ? "near" : "testnet";
export const NATIVE_TOKEN_ID = "near";
Expand Down
5 changes: 2 additions & 3 deletions src/common/contracts/social/client.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { StorageCache, buildTransaction } from "@wpdas/naxios";
import { buildTransaction } from "@wpdas/naxios";

import { SOCIAL_DB_CONTRACT_ACCOUNT_ID } from "@/common/_config";
import { naxiosInstance } from "@/common/api/near/client";
Expand All @@ -9,7 +9,6 @@ import { AccountId } from "@/common/types";
*/
const nearSocialDbContractApi = naxiosInstance.contractApi({
contractId: SOCIAL_DB_CONTRACT_ACCOUNT_ID,
cache: new StorageCache({ expirationTime: 5 * 60 }), // 5 minutes
});

interface NEARSocialUserProfileInput {
Expand Down Expand Up @@ -99,7 +98,7 @@ export interface RegistrationSocialProfile {
}

type NEARSocialGetResponse = {
[key: string]: {
[key: AccountId]: {
profile?: NEARSocialUserProfile;
};
};
Expand Down
7 changes: 1 addition & 6 deletions src/common/contracts/social/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,5 @@ export const useSocialProfile = ({
accountId,
}: ByAccountId & ConditionalActivation) =>
useSWR(["useSocialProfile", accountId], ([_queryKey, account_id]) =>
!enabled
? undefined
: contractClient
.getSocialProfile({ accountId: account_id })
//? Handling `null` response
.then((response) => response ?? undefined),
!enabled ? undefined : contractClient.getSocialProfile({ accountId: account_id }),
);
34 changes: 0 additions & 34 deletions src/common/lib/deepObjectDiff.ts

This file was deleted.

3 changes: 2 additions & 1 deletion src/common/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
export * from "./string";
export { formatWithCommas } from "./formatWithCommas";
export * from "./formatWithCommas";
export * from "./format";
export * from "./id";
export * from "./navigation";
export * from "./daysAgo";
export * from "./object";
export * from "./numeric";
export * from "./datetime";
export * from "./protocol-config";
46 changes: 46 additions & 0 deletions src/common/lib/object.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
type DeepPartial<T> = T extends object
? {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
}
: T;

// TODO: Find a way to resolve `any` without sacrificing type safety
export const deepObjectDiff = <T extends Record<string, any>>(
objOriginal: T,
objUpdated: T,
): DeepPartial<T> => {
if (!objUpdated) objUpdated = {} as T;
const diff = {} as DeepPartial<T>;

function findDiff<U extends Record<string, any>>(
original: U | undefined,
updated: U,
diffObj: DeepPartial<U>,
): DeepPartial<U> {
Object.keys(updated).forEach((key: string) => {
const updatedValue = updated[key];
const originalValue = original ? original[key] : undefined;

// If both values are objects, recurse.
if (
typeof updatedValue === "object" &&
updatedValue !== null &&
(originalValue === undefined ||
(typeof originalValue === "object" && originalValue !== null))
) {
const nestedDiff = originalValue ? findDiff(originalValue, updatedValue, {}) : updatedValue;

if (Object.keys(nestedDiff).length > 0) {
(diffObj as Record<string, unknown>)[key] = nestedDiff;
}
} else if (updatedValue !== originalValue) {
// Direct comparison for string values.
(diffObj as Record<string, unknown>)[key] = updatedValue;
}
});

return diffObj;
}

return findDiff(objOriginal, objUpdated, diff);
};
15 changes: 13 additions & 2 deletions src/common/services/ipfs.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,19 @@
const uploadFileToIPFS = async (body: BodyInit) =>
import { IPFS_NEAR_SOCIAL_URL } from "../constants";

export const nearSocialIpfsUpload = async (body: BodyInit) =>
fetch("https://ipfs.near.social/add", {
method: "POST",
headers: { Accept: "application/json" },
body,
});

export default uploadFileToIPFS;
export const nearSocialIpfsImageUpload = async (files: File[]) =>
nearSocialIpfsUpload(files[0]).then((response) => {
console.log(response);

if (response.ok) {
return response
.json()
.then((data) => ("cid" in data ? `${IPFS_NEAR_SOCIAL_URL}${data.cid}` : undefined));
}
});
3 changes: 2 additions & 1 deletion src/common/ui/components/atoms/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,13 @@ export interface ButtonProps
}

const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
({ className, variant, font, size, asChild = false, ...props }, ref) => {
({ className, variant, font, size, asChild = false, type = "button", ...props }, ref) => {
const Comp = asChild ? Slot : "button";
return (
<Comp
className={cn(buttonVariants({ variant, size, font, className }))}
ref={ref}
type={type}
{...props}
/>
);
Expand Down
19 changes: 15 additions & 4 deletions src/entities/_shared/account/components/AccountGroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export const AccountGroup: React.FC<AccountGroupProps> = ({
const { value: accountIds } = props;
const isEditingEnabled = isEditable && "title" in props;
const modalId = useId();

const openAccountsModal = useCallback(() => show(modalId), [modalId]);

const accountList = useMemo(
Expand All @@ -50,24 +49,36 @@ export const AccountGroup: React.FC<AccountGroupProps> = ({
{...{ accountId: account.accountId }}
/>
))}

{accountIds.length > 4 && (
<div
style={{
boxShadow: "rgba(100, 100, 111, 0.2) 0px 7px 29px 0px",
}}
className={cn(
"z-999 group relative flex items-center justify-center rounded-full border-2 border-white bg-red-500 px-3 py-3 text-sm font-semibold text-white transition-all duration-500 ease-in-out",
"z-999 group relative flex items-center justify-center",
"rounded-full border-2 border-white bg-red-500 px-3 py-3",
"text-sm font-semibold text-white transition-all duration-500 ease-in-out",
classNames?.avatar,
)}
>
<span className="text-[11px] font-bold">{accountIds.length - 4}+</span>
<div className="z-9999 bg-background absolute top-4 mt-2 hidden max-h-80 w-48 w-max overflow-y-auto rounded-md py-4 shadow-lg transition-all duration-500 ease-in-out group-hover:block">

<div
className={cn(
"z-9999 bg-background absolute top-4 mt-2 hidden",
"max-h-80 w-48 w-max overflow-y-auto rounded-md py-4",
"shadow-lg transition-all duration-500 ease-in-out group-hover:block",
)}
>
{accountIds.slice(4).map((account) => (
<Link
href={`/profile/${account.accountId}`}
target="_blank"
key={account.accountId}
className="mb-2 flex cursor-pointer items-center gap-2 p-2 text-[#292929] hover:bg-gray-100"
className={
"mb-2 flex cursor-pointer items-center gap-2 p-2 text-[#292929] hover:bg-gray-100"
}
>
<AccountProfilePicture accountId={account.accountId} className="h-5 w-5" />
{account.accountId}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ import {
} from "@/common/ui/components";
import { TextField } from "@/common/ui/form-fields";
import { cn } from "@/common/ui/utils";
import { AccountKey, AccountListItem, validAccountId } from "@/entities/_shared/account";
import { AccountGroupItem, AccountListItem, validAccountId } from "@/entities/_shared/account";

export type AccountGroupEditModalProps = {
title: string;
value: AccountKey[];
value: AccountGroupItem[];
onSubmit: (accountIds: AccountId[]) => void;
handleRemoveAccounts?: (accounts: AccountKey[]) => void;
handleRemoveAccounts?: (accounts: AccountGroupItem[]) => void;
footer?: React.ReactNode;
maxAccounts?: number;
};
Expand Down
11 changes: 10 additions & 1 deletion src/entities/_shared/account/constants.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import { IMAGES_ASSET_ENDPOINT_URL } from "@/common/constants";
import { RegistrationStatus } from "@/common/contracts/core";

import type { AccountProfileLinktreeKey } from "./types";

export const ACCOUNT_PROFILE_IMAGE_PLACEHOLDER_SRC = `${IMAGES_ASSET_ENDPOINT_URL}/profile-image.png`;

export const ACCOUNT_PROFILE_COVER_IMAGE_PLACEHOLDER_SRC = `${IMAGES_ASSET_ENDPOINT_URL}/profile-banner.png`;

export const ACCOUNT_PROFILE_URL_PATTERNS = {
export const ACCOUNT_PROFILE_LINKTREE_KEYS: AccountProfileLinktreeKey[] = [
"github",
"telegram",
"twitter",
"website",
];

export const ACCOUNT_PROFILE_URL_PATTERNS: Record<AccountProfileLinktreeKey, RegExp> = {
github: /^(?:https?:\/\/)?(?:www\.)?github\.com\/([^/]+(?:\/[^/]+)?)\/?$/,
twitter: /^(?:https?:\/\/)?(?:www\.)?x\.com\/([^/]+(?:\/[^/]+)?)\/?$/,
telegram: /^(?:https?:\/\/)?(?:www\.)?t\.com\/([^/]+(?:\/[^/]+)?)\/?$/,
Expand Down
Loading
Loading