A decentralized music tracking and discovery platform built on AT Protocol 🎵

fix: update import statement for Key type in Profile.tsx

+183 -184
+183 -184
apps/web/src/pages/profile/Profile.tsx
··· 7 7 import dayjs from "dayjs"; 8 8 import { useAtom, useSetAtom } from "jotai"; 9 9 import _ from "lodash"; 10 - import { Key, useEffect, useState } from "react"; 10 + import { type Key, useEffect, useState } from "react"; 11 11 import { profilesAtom } from "../../atoms/profiles"; 12 12 import { userAtom } from "../../atoms/user"; 13 13 import Shout from "../../components/Shout/Shout"; ··· 26 26 `; 27 27 28 28 export type ProfileProps = { 29 - activeKey?: string; 29 + activeKey?: string; 30 30 }; 31 31 32 32 function Profile(props: ProfileProps) { 33 - const [profiles, setProfiles] = useAtom(profilesAtom); 34 - const [activeKey, setActiveKey] = useState<Key>( 35 - _.get(props, "activeKey", "0").split("/")[0], 36 - ); 37 - const { did } = useParams({ strict: false }); 38 - const profile = useProfileByDidQuery(did!); 39 - const setUser = useSetAtom(userAtom); 40 - const { tab } = useSearch({ strict: false }); 33 + const [profiles, setProfiles] = useAtom(profilesAtom); 34 + const [activeKey, setActiveKey] = useState<Key>( 35 + _.get(props, "activeKey", "0").split("/")[0], 36 + ); 37 + const { did } = useParams({ strict: false }); 38 + const profile = useProfileByDidQuery(did!); 39 + const setUser = useSetAtom(userAtom); 40 + const { tab } = useSearch({ strict: false }); 41 41 42 - useEffect(() => { 43 - if (!tab) { 44 - return; 45 - } 42 + useEffect(() => { 43 + if (tab === undefined) { 44 + return; 45 + } 46 46 47 - setActiveKey(1); 48 - }, [tab]); 47 + setActiveKey(1); 48 + }, [tab]); 49 49 50 - useEffect(() => { 51 - if (profile.isLoading || profile.isError) { 52 - return; 53 - } 50 + // biome-ignore lint/correctness/useExhaustiveDependencies: <reason>want to run only on profile.data changes</reason> 51 + useEffect(() => { 52 + if (profile.isLoading || profile.isError) { 53 + return; 54 + } 54 55 55 - if (!profile.data || !did) { 56 - return; 57 - } 56 + if (!profile.data || !did) { 57 + return; 58 + } 58 59 59 - setUser({ 60 - avatar: profile.data.avatar, 61 - displayName: profile.data.displayName, 62 - handle: profile.data.handle, 63 - spotifyUser: { 64 - isBeta: profile.data.spotifyUser?.isBetaUser, 65 - }, 66 - spotifyConnected: profile.data.spotifyConnected, 67 - did: profile.data.did, 68 - }); 60 + setUser({ 61 + avatar: profile.data.avatar, 62 + displayName: profile.data.displayName, 63 + handle: profile.data.handle, 64 + spotifyUser: { 65 + isBeta: profile.data.spotifyUser?.isBetaUser, 66 + }, 67 + spotifyConnected: profile.data.spotifyConnected, 68 + did: profile.data.did, 69 + }); 69 70 70 - setProfiles((profiles) => ({ 71 - ...profiles, 72 - [did]: { 73 - avatar: profile.data.avatar, 74 - displayName: profile.data.displayName, 75 - handle: profile.data.handle, 76 - spotifyConnected: profile.data.spotifyConnected, 77 - createdAt: profile.data.createdAt, 78 - did, 79 - }, 80 - })); 81 - // eslint-disable-next-line react-hooks/exhaustive-deps 82 - }, [profile.data, profile.isLoading, profile.isError, did]); 71 + setProfiles((profiles) => ({ 72 + ...profiles, 73 + [did]: { 74 + avatar: profile.data.avatar, 75 + displayName: profile.data.displayName, 76 + handle: profile.data.handle, 77 + spotifyConnected: profile.data.spotifyConnected, 78 + createdAt: profile.data.createdAt, 79 + did, 80 + }, 81 + })); 82 + // eslint-disable-next-line react-hooks/exhaustive-deps 83 + }, [profile.data, profile.isLoading, profile.isError, did]); 83 84 84 - if (!did) { 85 - return <></>; 86 - } 85 + if (!did) { 86 + return; 87 + } 87 88 88 - return ( 89 - <> 90 - <Main> 91 - <div className="pb-[100px] pt-[75px]"> 92 - <Group> 93 - <div className="mr-[20px]"> 94 - <Avatar 95 - name={profiles[did]?.displayName} 96 - src={profiles[did]?.avatar} 97 - size="150px" 98 - /> 99 - </div> 100 - <div style={{ marginTop: profiles[did]?.displayName ? 10 : 30 }}> 101 - <HeadingMedium 102 - marginTop="0px" 103 - marginBottom={0} 104 - className="!text-[var(--color-text)]" 105 - > 106 - {profiles[did]?.displayName} 107 - </HeadingMedium> 108 - <LabelLarge> 109 - <a 110 - href={`https://bsky.app/profile/${profiles[did]?.handle}`} 111 - className="no-underline text-[var(--color-primary)]" 112 - > 113 - @{profiles[did]?.handle} 114 - </a> 115 - <span className="text-[var(--color-text-muted)] text-[15px]"> 116 - {" "} 117 - • scrobbling since{" "} 118 - {dayjs(profiles[did]?.createdAt).format("DD MMM YYYY")} 119 - </span> 120 - </LabelLarge> 121 - <div className="flex-1 mt-[30px] mr-[10px]"> 122 - <a 123 - href={`https://pdsls.dev/at/${profiles[did]?.did}`} 124 - target="_blank" 125 - className="no-underline text-[var(--color-text)] bg-[var(--color-default-button)] p-[16px] rounded-[10px] pl-[25px] pr-[25px]" 126 - > 127 - <ExternalLink size={24} style={{ marginRight: 10 }} /> 128 - View on PDSls 129 - </a> 130 - </div> 131 - </div> 132 - </Group> 89 + return ( 90 + <Main> 91 + <div className="pb-[100px] pt-[75px]"> 92 + <Group> 93 + <div className="mr-[20px]"> 94 + <Avatar 95 + name={profiles[did]?.displayName} 96 + src={profiles[did]?.avatar} 97 + size="150px" 98 + /> 99 + </div> 100 + <div style={{ marginTop: profiles[did]?.displayName ? 10 : 30 }}> 101 + <HeadingMedium 102 + marginTop="0px" 103 + marginBottom={0} 104 + className="!text-[var(--color-text)]" 105 + > 106 + {profiles[did]?.displayName} 107 + </HeadingMedium> 108 + <LabelLarge> 109 + <a 110 + href={`https://bsky.app/profile/${profiles[did]?.handle}`} 111 + className="no-underline text-[var(--color-primary)]" 112 + > 113 + @{profiles[did]?.handle} 114 + </a> 115 + <span className="text-[var(--color-text-muted)] text-[15px]"> 116 + {" "} 117 + • scrobbling since{" "} 118 + {dayjs(profiles[did]?.createdAt).format("DD MMM YYYY")} 119 + </span> 120 + </LabelLarge> 121 + <div className="flex-1 mt-[30px] mr-[10px]"> 122 + <a 123 + href={`https://pdsls.dev/at/${profiles[did]?.did}`} 124 + target="_blank" 125 + className="no-underline text-[var(--color-text)] bg-[var(--color-default-button)] p-[16px] rounded-[10px] pl-[25px] pr-[25px]" 126 + > 127 + <ExternalLink size={24} style={{ marginRight: 10 }} /> 128 + View on PDSls 129 + </a> 130 + </div> 131 + </div> 132 + </Group> 133 133 134 - <Tabs 135 - activeKey={activeKey} 136 - onChange={({ activeKey }) => { 137 - setActiveKey(activeKey); 138 - }} 139 - overrides={{ 140 - TabHighlight: { 141 - style: { 142 - backgroundColor: "var(--color-purple)", 143 - }, 144 - }, 145 - TabBorder: { 146 - style: { 147 - display: "none", 148 - }, 149 - }, 150 - }} 151 - activateOnFocus 152 - > 153 - <Tab 154 - title="Overview" 155 - overrides={{ 156 - Tab: { 157 - style: { 158 - color: "var(--color-text)", 159 - backgroundColor: "var(--color-background) !important", 160 - }, 161 - }, 162 - }} 163 - > 164 - <Overview /> 165 - </Tab> 166 - <Tab 167 - title="Library" 168 - overrides={{ 169 - Tab: { 170 - style: { 171 - color: "var(--color-text)", 172 - backgroundColor: "var(--color-background) !important", 173 - }, 174 - }, 175 - }} 176 - > 177 - <Library 178 - activeKey={_.get(props, "activeKey", "0").split("/")[1] || "0"} 179 - /> 180 - </Tab> 181 - <Tab 182 - title="Playlists" 183 - overrides={{ 184 - Tab: { 185 - style: { 186 - color: "var(--color-text)", 187 - backgroundColor: "var(--color-background) !important", 188 - }, 189 - }, 190 - }} 191 - > 192 - <Playlists /> 193 - </Tab> 194 - <Tab 195 - title="Loved Tracks" 196 - overrides={{ 197 - Tab: { 198 - style: { 199 - color: "var(--color-text)", 200 - backgroundColor: "var(--color-background) !important", 201 - }, 202 - }, 203 - }} 204 - > 205 - <LovedTracks /> 206 - </Tab> 207 - <Tab 208 - title="Tags" 209 - overrides={{ 210 - Tab: { 211 - style: { 212 - color: "var(--color-text)", 213 - backgroundColor: "var(--color-background) !important", 214 - }, 215 - }, 216 - }} 217 - ></Tab> 218 - </Tabs> 219 - <Shout type="profile" /> 220 - </div> 221 - </Main> 222 - </> 223 - ); 134 + <Tabs 135 + activeKey={activeKey} 136 + onChange={({ activeKey }) => { 137 + setActiveKey(activeKey); 138 + }} 139 + overrides={{ 140 + TabHighlight: { 141 + style: { 142 + backgroundColor: "var(--color-purple)", 143 + }, 144 + }, 145 + TabBorder: { 146 + style: { 147 + display: "none", 148 + }, 149 + }, 150 + }} 151 + activateOnFocus 152 + > 153 + <Tab 154 + title="Overview" 155 + overrides={{ 156 + Tab: { 157 + style: { 158 + color: "var(--color-text)", 159 + backgroundColor: "var(--color-background) !important", 160 + }, 161 + }, 162 + }} 163 + > 164 + <Overview /> 165 + </Tab> 166 + <Tab 167 + title="Library" 168 + overrides={{ 169 + Tab: { 170 + style: { 171 + color: "var(--color-text)", 172 + backgroundColor: "var(--color-background) !important", 173 + }, 174 + }, 175 + }} 176 + > 177 + <Library 178 + activeKey={_.get(props, "activeKey", "0").split("/")[1] || "0"} 179 + /> 180 + </Tab> 181 + <Tab 182 + title="Playlists" 183 + overrides={{ 184 + Tab: { 185 + style: { 186 + color: "var(--color-text)", 187 + backgroundColor: "var(--color-background) !important", 188 + }, 189 + }, 190 + }} 191 + > 192 + <Playlists /> 193 + </Tab> 194 + <Tab 195 + title="Loved Tracks" 196 + overrides={{ 197 + Tab: { 198 + style: { 199 + color: "var(--color-text)", 200 + backgroundColor: "var(--color-background) !important", 201 + }, 202 + }, 203 + }} 204 + > 205 + <LovedTracks /> 206 + </Tab> 207 + <Tab 208 + title="Tags" 209 + overrides={{ 210 + Tab: { 211 + style: { 212 + color: "var(--color-text)", 213 + backgroundColor: "var(--color-background) !important", 214 + }, 215 + }, 216 + }} 217 + ></Tab> 218 + </Tabs> 219 + <Shout type="profile" /> 220 + </div> 221 + </Main> 222 + ); 224 223 } 225 224 226 225 export default Profile;