Skip to content

Commit

Permalink
🐡🪐 ↝ Updated styling for Lens client (basic css for now) & added dyna…
Browse files Browse the repository at this point in the history
…mic routes for profile loading

Signal-K/Silfur#24 & #16
  • Loading branch information
Gizmotronn committed Jan 3, 2023
1 parent b84a27c commit 7818816
Show file tree
Hide file tree
Showing 12 changed files with 323 additions and 151 deletions.
Binary file modified .DS_Store
Binary file not shown.
39 changes: 39 additions & 0 deletions Server/frontend/components/FeedPost.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { MediaRenderer } from '@thirdweb-dev/react';
import Link from 'next/link';
import React from 'react';
import { ExplorePublicationsQuery } from '../graphql/generated';
import styles from '../styles/FeedPost.module.css';

type Props = {
publication: ExplorePublicationsQuery["explorePublications"]["items"][0];
}

export default function FeedPost ({publication}: Props) {
return (
<div className={styles.feedPostContainer}>
<div className={styles.feedPostHeader}>
<MediaRenderer
// @ts-ignore
src={publication?.profile?.picture?.original?.url}
alt={publication.profile.name || publication.profile.handle}
className={styles.feedPostProfilePicture}
/>
<Link href={`/profile/${publication.profile.handle}`} className={styles.feedPostProfileName}>
{publication.profile.name || publication.profile.handle}
</Link>
</div>
<div className={styles.feedPostContent}>
<h3 className={styles.feedPostContentTitle}>{publication.metadata.name}</h3>
<p className={styles.feedPostContentDescription}>{publication.metadata.content}</p>

{ publication.metadata.media?.length > 0 && (
<MediaRenderer
src={publication.metadata.media[0].original.url}
alt={publication.metadata.name || ""}
className={styles.feedPostContentImage}
/>
)}
</div>
</div>
);
};
93 changes: 93 additions & 0 deletions Server/frontend/graphql/generated.ts

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions Server/frontend/graphql/get-profile.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
query profile($request: SingleProfileQueryRequest!) {
profile(request: $request) {
...ProfileFields
}
}
19 changes: 19 additions & 0 deletions Server/frontend/graphql/get-publications.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
query publications($request: PublicationsQueryRequest!) {
publications(request: $request) {
items {
__typename
... on Post {
...PostFields
}
... on Comment {
...CommentFields
}
... on Mirror {
...MirrorFields
}
}
pageInfo {
...CommonPaginatedResultInfoFields
}
}
}
47 changes: 39 additions & 8 deletions Server/frontend/lib/auth/refreshAccessToken.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,53 @@ import { fetcher } from "../../graphql/auth-fetcher";
import { RefreshMutation, RefreshMutationVariables, RefreshDocument } from "../../graphql/generated";
import { readAccessToken, setAccessToken } from "./helpers";


export default async function refreshAccessToken () { // Take current refresh, access token to Lens to generate a new Access token
// Read refresh token from local storage
const currentRefreshToken = readAccessToken()?.refreshToken;
if (!currentRefreshToken) return null;

// Send refresh token to Lens
const result = await fetcher<RefreshMutation, RefreshMutationVariables>(RefreshDocument, {
request: {
refreshToken: currentRefreshToken
async function fetchData<TData, Tvariables>(
query: string,
variables?: Tvariables,
options?: RequestInit['headers']
): Promise<TData> {
const res = await fetch('https://api.lens.dev', {
method: "POST",
headers: {
'Content-Type': 'application/json',
...options,
'Access-Control-Allow-Origin': "*",
},
})();
body: JSON.stringify({
query,
variables,
}),
});

const json = await res.json();

if (json.errors) {
const { message } = json.errors[0] || {};
throw new Error(message || "Error...");
};

return json.data;
};

// Set new refresh token
const {
accessToken, refreshToken: newRefreshToken
} = result.refresh;
const result = await fetchData<
RefreshMutation, RefreshMutationVariables
>(RefreshDocument, {
request: {
refreshToken: currentRefreshToken,
},
});
const {
refresh: {
accessToken, refreshToken: newRefreshToken
}
} = result;
setAccessToken(accessToken, newRefreshToken);

return accessToken as string;
Expand Down
28 changes: 10 additions & 18 deletions Server/frontend/lib/auth/useLogin.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useMutation } from "@apollo/client";
import { useQueryClient, useMutation } from "@tanstack/react-query";
import { useAddress, useSDK } from "@thirdweb-dev/react";
import { useAuthenticateMutation } from "../../graphql/generated";
import generateChallenge from "./generateChallenge";
Expand All @@ -9,32 +9,24 @@ import { setAccessToken } from "./helpers";
export default function useLogin() {
const address = useAddress(); // Ensure user has connected wallet
const sdk = useSDK();
const {
mutateAsync: sendSignedMessage
} = useAuthenticateMutation();
const { mutateAsync: sendSignedMessage } = useAuthenticateMutation();
const client = useQueryClient();

async function login () {
if (!address) {
console.error('No address found. Please try connecting your wallet to continue signing into Lens');
return null;
}

const { challenge } = await generateChallenge(address); // Generate challenge from the Lens API
const signature = await sdk?.wallet.sign(challenge.text); // Sign the returned challenge with the user's wallet
const { // Send the signed challenge to the Lens API
authenticate
} = await sendSignedMessage({
async function login() {
if (!address) return;
const { challenge } = await generateChallenge(address); // Generate a challenge (for auth) from Lens API
const signature = await sdk?.wallet.sign(challenge.text); // Sign the challenge
const { authenticate } = await sendSignedMessage({
request: {
address,
signature,
},
});

const { accessToken, refreshToken} = authenticate;

const { accessToken, refreshToken } = authenticate;
setAccessToken(accessToken, refreshToken);
client.invalidateQueries(['lens-user', address]);
}

// Receive an access token from Lens API
return useMutation(login);
}
37 changes: 30 additions & 7 deletions Server/frontend/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,34 @@
import type { NextPage } from "next";
import useAuthenticate from '../hooks/useAuthenticate';
import { useAddress, useDisconnect, useUser, useLogout, useMetamask, ConnectWallet } from "@thirdweb-dev/react";
import { useEffect, useState } from "react";
import { PublicationSortCriteria, useExplorePublicationsQuery } from "../graphql/generated";
import useLogin from "../lib/auth/useLogin";
import FeedPost from "../components/FeedPost";
import SignInButton from "../components/SignInButton";
import { PublicationSortCriteria, useExplorePublicationsQuery } from "../graphql/generated";
import styles from '../styles/Home.module.css';

export default function Home () {
return <SignInButton />;
const { isLoading, error, data } = useExplorePublicationsQuery({
request: {
sortCriteria: PublicationSortCriteria.TopCollected,
},
},
{
refetchOnWindowFocus: false,
refetchOnReconnect: false,
});

if (isLoading) {
return (<div className={styles.container}>Loading</div>)
};

if (error) {
return (<div className={styles.container}>Error</div>)
};

return (
<div className={styles.container}>
<div className={styles.postContainer}>
{data?.explorePublications.items.map((publication) => (
<FeedPost publication={publication} key={publication.id} />
))};
</div>
</div>
);
};
37 changes: 37 additions & 0 deletions Server/frontend/pages/profile/[id].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { useRouter } from 'next/router';
import React from 'react';
import { useProfileQuery, usePublicationsQuery } from '../../graphql/generated';
import styles from '../../styles/Profile.module.css';

type Props = {}

export default function ProfilePage({}: Props) {
const router = useRouter();
const { id } = router.query;
const { isLoading: loadingProfile, data: profileData } = useProfileQuery({
request: {
handle: id,
},
}, {
enabled: !!id,
});

const { isLoading: isLoadingPublications, data: publicationsData } = usePublicationsQuery({
request: {
profileId: profileData?.profile?.id
},
}, {
enabled: !!profileData?.profile?.id,
});

return (
<div className={styles.profileContainer}>
<div className={styles.profileContentContainer}>

</div>
<div className={styles.publicationsContainer}>

</div>
</div>
)
}
48 changes: 48 additions & 0 deletions Server/frontend/styles/FeedPost.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
.feedPostContainer {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background-color: rgba(30, 30, 30, 0.9);
border: 1px solid black;
border-radius: 10px;
padding: 16px;
margin-bottom: 16px;
width: 100%;
gap: 16px;
text-align: center;
}

.feedPostHeader {
display: flex;
flex-direction: row;
align-items: center;
justify-content: flex-start;
gap: 12px;
}

.feedPostProfilePicture {
border-radius: 50%;
width: 48px;
height: 48px;
border: 1px solid black;
}

.feedPostProfileName {
font-size: 16px;
font-weight: 600;
}

.feedPostContentImage {
height: 256px;
}

.feedPostContentTitle {
font-size: 24px;
font-weight: 600;
}

.feedPostContentDescription {
font-size: 16px;
font-weight: 400;
}
Loading

0 comments on commit 7818816

Please sign in to comment.