Skip to content

Commit

Permalink
feat: add avatar & display name
Browse files Browse the repository at this point in the history
  • Loading branch information
kawamataryo committed Jan 11, 2025
1 parent 684218a commit e455fea
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 313 deletions.
60 changes: 36 additions & 24 deletions src/components/popup/SearchForm.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,51 @@
interface SearchFormProps {
isLoading: boolean;
displayName: string;
avatar: string;
onSubmit: (e: React.FormEvent) => void;
onLogout: () => void;
}

export const SearchForm = ({
isLoading,
displayName,
avatar,
onSubmit,
onLogout,
}: SearchFormProps) => {
return (
<div className="mt-5">
<div className="mt-5 flex flex-col gap-3">
<div className="flex justify-end gap-2">
<div className="flex gap-1 items-center">
<img
src={avatar}
alt={displayName}
className="w-5 h-5 rounded-full"
/>
<span className="text-sm max-w-[150px] truncate">{displayName}</span>
</div>
<button
type="button"
onClick={onLogout}
className="text-sm dark:hover:text-gray-200 flex gap-1 items-center"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="w-4 h-4"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M15.75 9V5.25A2.25 2.25 0 0 0 13.5 3h-6a2.25 2.25 0 0 0-2.25 2.25v13.5A2.25 2.25 0 0 0 7.5 21h6a2.25 2.25 0 0 0 2.25-2.25V15m3 0 3-3m0 0-3-3m3 3H9"
/>
</svg>
{chrome.i18n.getMessage("logout")}
</button>
</div>
<form onSubmit={onSubmit}>
<button
type="submit"
Expand Down Expand Up @@ -42,29 +77,6 @@ export const SearchForm = ({
: chrome.i18n.getMessage("find_bluesky_users")}
</button>
</form>
<div className="flex justify-end mt-2">
<button
type="button"
onClick={onLogout}
className="text-sm text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 flex gap-1 items-center"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
stroke="currentColor"
className="w-4 h-4"
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M15.75 9V5.25A2.25 2.25 0 0 0 13.5 3h-6a2.25 2.25 0 0 0-2.25 2.25v13.5A2.25 2.25 0 0 0 7.5 21h6a2.25 2.25 0 0 0 2.25-2.25V15m3 0 3-3m0 0-3-3m3 3H9"
/>
</svg>
{chrome.i18n.getMessage("logout")}
</button>
</div>
</div>
);
};
7 changes: 7 additions & 0 deletions src/lib/bskyClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,17 @@ export class BskyClient {
};

public getMyProfile = async () => {
const profile = await this.agent.getProfile({
actor: this.me.did,
});
console.log(profile.data);
return {
pdsUrl: this.agent.pdsUrl,
did: this.agent.session.did,
handle: this.agent.session.handle,
displayName: profile.data.displayName,
description: profile.data.description,
avatar: profile.data.avatar,
};
};
}
111 changes: 75 additions & 36 deletions src/lib/hooks/useAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import {
RATE_LIMIT_ERROR_MESSAGE,
STORAGE_KEYS,
} from "~lib/constants";
import {
getFromChromeStorage,
removeFromChromeStorage,
setToChromeStorage,
} from "~lib/utils";

interface Message {
type: (typeof MESSAGE_TYPE)[keyof typeof MESSAGE_TYPE];
Expand All @@ -25,47 +30,56 @@ export const useAuth = () => {
useState(false);
const [message, setMessage] = useState<Message | null>(null);
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [isAuthenticatedLoading, setIsAuthenticatedLoading] =
useState(true);
const [isAuthenticatedLoading, setIsAuthenticatedLoading] = useState(true);
const [displayName, setDisplayName] = useState("");
const [avatar, setAvatar] = useState("");

const setErrorMessage = (message: string, documentLink?: string) => {
setMessage({ type: MESSAGE_TYPE.ERROR, message, documentLink });
};
const setErrorMessage = useCallback(
(message: string, documentLink?: string) => {
setMessage({ type: MESSAGE_TYPE.ERROR, message, documentLink });
},
[],
);

const saveCredentialsToStorage = async () => {
await chrome.storage.local.set({
[STORAGE_KEYS.BSKY_USER_ID]: identifier,
[STORAGE_KEYS.BSKY_PASSWORD]: password,
});
await setToChromeStorage(STORAGE_KEYS.BSKY_USER_ID, identifier);
await setToChromeStorage(STORAGE_KEYS.BSKY_PASSWORD, password);
};

const clearPasswordFromStorage = async () => {
await chrome.storage.local.remove([STORAGE_KEYS.BSKY_PASSWORD]);
await removeFromChromeStorage(STORAGE_KEYS.BSKY_PASSWORD);
};

const saveShowAuthFactorTokenInputToStorage = async (value: boolean) => {
await chrome.storage.local.set({
[STORAGE_KEYS.BSKY_SHOW_AUTH_FACTOR_TOKEN_INPUT]: value,
});
await setToChromeStorage(
STORAGE_KEYS.BSKY_SHOW_AUTH_FACTOR_TOKEN_INPUT,
value,
);
};

const saveSessionToStorage = async (session: string) => {
await setToChromeStorage(STORAGE_KEYS.BSKY_CLIENT_SESSION, session);
};

const loadCredentialsFromStorage = useCallback(async () => {
chrome.storage.local.get(
[
STORAGE_KEYS.BSKY_USER_ID,
STORAGE_KEYS.BSKY_PASSWORD,
STORAGE_KEYS.BSKY_SHOW_AUTH_FACTOR_TOKEN_INPUT,
STORAGE_KEYS.BSKY_CLIENT_SESSION,
],
(result) => {
setIdentifier(result[STORAGE_KEYS.BSKY_USER_ID] || "");
setPassword(result[STORAGE_KEYS.BSKY_PASSWORD] || "");
setIsShowAuthFactorTokenInput(
result[STORAGE_KEYS.BSKY_SHOW_AUTH_FACTOR_TOKEN_INPUT] || false,
);
setIsAuthenticated(!!result[STORAGE_KEYS.BSKY_CLIENT_SESSION]);
},
const storage = await getFromChromeStorage([
STORAGE_KEYS.BSKY_USER_ID,
STORAGE_KEYS.BSKY_PASSWORD,
STORAGE_KEYS.BSKY_SHOW_AUTH_FACTOR_TOKEN_INPUT,
STORAGE_KEYS.BSKY_CLIENT_SESSION,
]);
setIdentifier(storage[STORAGE_KEYS.BSKY_USER_ID] || "");
setPassword(storage[STORAGE_KEYS.BSKY_PASSWORD] || "");
setIsShowAuthFactorTokenInput(
storage[STORAGE_KEYS.BSKY_SHOW_AUTH_FACTOR_TOKEN_INPUT] || false,
);
return {
identifier: storage[STORAGE_KEYS.BSKY_USER_ID],
password: storage[STORAGE_KEYS.BSKY_PASSWORD],
session: storage[STORAGE_KEYS.BSKY_CLIENT_SESSION],
isShowAuthFactorTokenInput:
storage[STORAGE_KEYS.BSKY_SHOW_AUTH_FACTOR_TOKEN_INPUT],
};
}, []);

const validateForm = () => {
Expand Down Expand Up @@ -93,7 +107,7 @@ export const useAuth = () => {
const logout = async () => {
setIsLoading(true);
try {
await chrome.storage.local.remove([
await removeFromChromeStorage([
STORAGE_KEYS.BSKY_CLIENT_SESSION,
STORAGE_KEYS.BSKY_PASSWORD,
STORAGE_KEYS.BSKY_SHOW_AUTH_FACTOR_TOKEN_INPUT,
Expand All @@ -120,7 +134,7 @@ export const useAuth = () => {
if (!validateForm()) {
return;
}
saveCredentialsToStorage();
await saveCredentialsToStorage();

setMessage(null);
setIsLoading(true);
Expand Down Expand Up @@ -157,10 +171,7 @@ export const useAuth = () => {
return;
}

await chrome.storage.local.set({
[STORAGE_KEYS.BSKY_CLIENT_SESSION]: session,
});

await saveSessionToStorage(session);
await clearPasswordFromStorage();
await saveShowAuthFactorTokenInputToStorage(false);
setIsAuthenticated(true);
Expand All @@ -175,8 +186,34 @@ export const useAuth = () => {
};

useEffect(() => {
loadCredentialsFromStorage();
setIsAuthenticatedLoading(false);
const initialize = async () => {
const { session } = await loadCredentialsFromStorage();
if (!session) {
setIsAuthenticated(false);
return;
}
const { result, error } = await sendToBackground({
name: "getMyProfile",
body: {
session,
},
});
if (error) {
setIsAuthenticated(false);
return;
}
setIsAuthenticated(true);
setDisplayName(result.displayName);
setAvatar(result.avatar);
};

initialize()
.catch(() => {
setIsAuthenticated(false);
})
.finally(() => {
setIsAuthenticatedLoading(false);
});
}, [loadCredentialsFromStorage]);

return {
Expand All @@ -191,6 +228,8 @@ export const useAuth = () => {
message,
isAuthenticated,
isAuthenticatedLoading,
displayName,
avatar,
login,
logout,
};
Expand Down
Loading

0 comments on commit e455fea

Please sign in to comment.