Skip to content

Commit

Permalink
Merge pull request #933 from lens-protocol/release-react-2.2.0
Browse files Browse the repository at this point in the history
chore: prepare release react 2.2.0
  • Loading branch information
krzysu committed May 3, 2024
2 parents 212d506 + ad6078c commit 23d80b3
Show file tree
Hide file tree
Showing 81 changed files with 11,032 additions and 1,207 deletions.
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
{
"eslint.workingDirectories": [
"examples/nextjs",
"examples/lens-next-app",
"examples/node",
"examples/react-native",
"examples/shared",
"examples/web",
"packages/api-bindings",
"packages/blockchain-bindings",
"packages/cli",
"packages/client",
"packages/domain",
"packages/eslint-config",
Expand Down
66 changes: 66 additions & 0 deletions examples/node/scripts/wallet/hideManagedProfile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { LensClient, ManagedProfileVisibility, development } from '@lens-protocol/client';

import { setupWallet } from '../shared/setupWallet';

/**
* Notice!
* Hide managed profile feature works only for managed profiles that are not owned by the wallet.
*/

async function fetchManagedNotOwnedProfiles(client: LensClient, address: string) {
const result = await client.wallet.profilesManaged({
for: address,
includeOwned: false, // important!
hiddenFilter: ManagedProfileVisibility.NoneHidden,
});

console.log(
`Profiles managed by ${address}: `,
result.items.map((item) => ({
id: item.id,
handle: item.handle,
})),
);

return result.items;
}

async function main() {
const client = new LensClient({
environment: development,
});

const wallet = setupWallet();
const address = await wallet.getAddress();

const profiles = await fetchManagedNotOwnedProfiles(client, address);

if (profiles.length === 0) {
console.log('No managed profiles found');
process.exit(0);
}

const profileIdToHide = profiles[0].id;

// Hide the first managed profile
console.log(`Hiding profile ${profileIdToHide} from managed profiles list`);

await client.wallet.hideManagedProfile({
profileId: profileIdToHide,
});

// Fetch managed profiles again
await fetchManagedNotOwnedProfiles(client, address);

// Unhide the profile
console.log(`Unhiding profile ${profileIdToHide}`);

await client.wallet.unhideManagedProfile({
profileId: profileIdToHide,
});

// Fetch managed profiles again
await fetchManagedNotOwnedProfiles(client, address);
}

main();
2 changes: 1 addition & 1 deletion examples/node/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true,
"target": "es6"
"target": "ESNext"
},
"include": ["scripts"],
"ts-node": {
Expand Down
2 changes: 2 additions & 0 deletions examples/web/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import {
UseProfileActionHistory,
UseProfileFollowers,
UseProfileFollowing,
UseProfileInterests,
UseProfileManagers,
UseProfiles,
UseRecommendProfileToggle,
Expand Down Expand Up @@ -151,6 +152,7 @@ export function App() {
<Route path="useBlockedProfiles" element={<UseBlockedProfiles />} />
<Route path="useReportProfile" element={<UseReportProfile />} />
<Route path="useRecommendProfileToggle" element={<UseRecommendProfileToggle />} />
<Route path="useProfileInterests" element={<UseProfileInterests />} />
</Route>

<Route path="/discovery">
Expand Down
5 changes: 5 additions & 0 deletions examples/web/src/profiles/ProfilesPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ const profileHooks = [
description: 'Recommend a profile.',
path: '/profiles/useRecommendProfileToggle',
},
{
label: 'useProfileInterests',
description: 'Add and remove profile interests.',
path: '/profiles/useProfileInterests',
},
];

export function ProfilesPage() {
Expand Down
40 changes: 34 additions & 6 deletions examples/web/src/profiles/UseProfile.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,43 @@
import { profileId, useProfile } from '@lens-protocol/react-web';
import { useProfile } from '@lens-protocol/react-web';
import { Suspense, startTransition, useState } from 'react';

import { ErrorMessage } from '../components/error/ErrorMessage';
import { Loading } from '../components/loading/Loading';
import { ProfileCard } from './components/ProfileCard';

export function UseProfileInner({ localName }: { localName: string }) {
const { data, error } = useProfile({ forHandle: `lens/${localName}`, suspense: true });

if (error) {
return <p>Profile not found.</p>;
}

return <ProfileCard profile={data} />;
}

export function UseProfile() {
const { data: profile, error, loading } = useProfile({ forProfileId: profileId('0x01') });
const [localName, setLocalName] = useState('brainjammer');

const update = (event: React.ChangeEvent<HTMLInputElement>) =>
startTransition(() => {
if (event.target.value.length > 0) {
setLocalName(event.target.value);
}
});

if (loading) return <Loading />;
return (
<div>
<h1>
<code>useProfile</code>
</h1>

if (error) return <ErrorMessage error={error} />;
<label>
lens/
<input type="text" name="localName" defaultValue={localName} onChange={update} />
</label>

return <ProfileCard profile={profile} />;
<Suspense fallback={<Loading />}>
<UseProfileInner localName={localName} />
</Suspense>
</div>
);
}
122 changes: 122 additions & 0 deletions examples/web/src/profiles/UseProfileInterests.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import {
useAddProfileInterests,
useRemoveProfileInterests,
ProfileInterestTypes,
Profile,
} from '@lens-protocol/react-web';
import { Fragment, useMemo } from 'react';

import { RequireProfileSession } from '../components/auth';

// Capitalizes each word in a string
function capitalize(label: string): string {
return label.toLowerCase().replace(/\b\w/g, (char) => char.toUpperCase());
}

type Interest = {
parent: string;
value: ProfileInterestTypes;
label: string;
};

// Processes raw interest types into structured interests array
function createInterests(categories: ProfileInterestTypes[]): Interest[] {
return categories.map((item) => {
const [parent, subcategory] = item.split('__');
const label = capitalize(
subcategory ? subcategory.replace(/_/g, ' ') : parent.replace(/_/g, ' '),
);
return { parent, value: item, label };
});
}

type ButtonProps = {
isActive: boolean;
onClick: () => void;
children: React.ReactNode;
};

function ToggleButton({ isActive, onClick, children }: ButtonProps) {
const normalStyle = {
backgroundColor: 'transparent',
border: '1px solid grey',
color: '#111',
outline: 'none',
};

const activeStyle = {
...normalStyle,
backgroundColor: '#333',
color: '#eee',
};

return (
<button style={isActive ? activeStyle : normalStyle} onClick={onClick}>
{children}
</button>
);
}

function UseProfileInterestsInner({ profile }: { profile: Profile }) {
const { execute: addInterests } = useAddProfileInterests();
const { execute: removeInterests } = useRemoveProfileInterests();

const groupedInterests = useMemo(() => {
const interests = createInterests(Object.values(ProfileInterestTypes));

// Group interests by category
return interests.reduce((acc, interest) => {
acc[interest.parent] = acc[interest.parent] || [];
acc[interest.parent].push(interest);
return acc;
}, {} as Record<string, Interest[]>);
}, []);

const handleClick = async (interest: ProfileInterestTypes) => {
const request = {
interests: [interest],
};

if (profile.interests.includes(interest)) {
await removeInterests(request);
} else {
await addInterests(request);
}
};

return (
<div>
{Object.entries(groupedInterests).map(([category, items]) => (
<div key={category}>
<h4>{capitalize(category.replace(/_/g, ' '))}</h4>
<div>
{items.map((item) => (
<Fragment key={item.value}>
<ToggleButton
onClick={() => handleClick(item.value)}
isActive={profile.interests.includes(item.value)}
>
{item.label}
</ToggleButton>{' '}
</Fragment>
))}
</div>
</div>
))}
</div>
);
}

export function UseProfileInterests() {
return (
<div>
<h2>
<code>useAddProfileInterests & useRemoveProfileInterests</code>
</h2>

<RequireProfileSession message="Log in to view this example.">
{({ profile }) => <UseProfileInterestsInner profile={profile} />}
</RequireProfileSession>
</div>
);
}
1 change: 1 addition & 0 deletions examples/web/src/profiles/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export * from './UseProfile';
export * from './UseProfileActionHistory';
export * from './UseProfileFollowers';
export * from './UseProfileFollowing';
export * from './UseProfileInterests';
export * from './UseProfileManagers';
export * from './UseProfiles';
export * from './UseRecommendProfileToggle';
Expand Down
9 changes: 9 additions & 0 deletions packages/api-bindings/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# @lens-protocol/api-bindings

## 0.12.1

### Patch Changes

- 2edd76361: **feat:** added globalStats alias to publication and profile stats
- Updated dependencies [b1e474862]
- Updated dependencies [1e6b96c67]
- @lens-protocol/domain@0.12.0

## 0.12.0

### Minor Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/api-bindings/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@lens-protocol/api-bindings",
"version": "0.12.0",
"version": "0.12.1",
"description": "Graphql fragments, react hooks, typescript types of lens API.",
"repository": {
"directory": "packages/api-bindings",
Expand Down
11 changes: 9 additions & 2 deletions packages/api-bindings/src/lens/__helpers__/fragments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ export function mockProfileFragment(overrides?: Partial<gql.Profile>): gql.Profi
metadata: null,
invitedBy: null,
stats: mockProfileStatsFragment(),
globalStats: mockProfileStatsFragment(),
peerToPeerRecommendedByMe: false,

...overrides,
Expand All @@ -138,8 +139,11 @@ export function mockProfileFragment(overrides?: Partial<gql.Profile>): gql.Profi
}

export function mockPostFragment(overrides?: Partial<Omit<gql.Post, '__typename'>>): gql.Post {
const publicationId = mockPublicationId();
const stats = mockPublicationStatsFragment({ id: publicationId });

return {
id: mockPublicationId(),
id: publicationId,
isHidden: false,
txHash: mockTransactionHash(),
by: mockProfileFragment(),
Expand All @@ -150,7 +154,8 @@ export function mockPostFragment(overrides?: Partial<Omit<gql.Post, '__typename'
metadata: mockPublicationTextOnlyMetadata(),
openActionModules: [],
referenceModule: null,
stats: mockPublicationStatsFragment(),
stats,
globalStats: stats,
isEncrypted: false,
hashtagsMentioned: [],
profilesMentioned: [],
Expand Down Expand Up @@ -182,6 +187,7 @@ export function mockCommentFragment(
commentOn: mainPost,
firstComment: null,
stats: mockPublicationStatsFragment(),
globalStats: mockPublicationStatsFragment(),
isEncrypted: false,
hashtagsMentioned: [],
profilesMentioned: [],
Expand All @@ -206,6 +212,7 @@ export function mockQuoteFragment(overrides?: Partial<Omit<gql.Quote, '__typenam
referenceModule: null,
quoteOn: mockPostFragment(),
stats: mockPublicationStatsFragment(),
globalStats: mockPublicationStatsFragment(),
isEncrypted: false,
hashtagsMentioned: [],
profilesMentioned: [],
Expand Down
Loading

0 comments on commit 23d80b3

Please sign in to comment.