Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 14 additions & 0 deletions src/app/(menu)/(public)/[username]/_components/Following.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
'use client';

import FollowList from '@/app/(menu)/(public)/[username]/_components/layouts/FollowList';
import { useFollowing } from '@/swr/client/follows';
import { UserWithFollows } from '@cuculus/cuculus-api';

/**
* フォロー一覧表示コンポーネント
* @param user
* @constructor
*/
export default function Following({ user }: { user: UserWithFollows }) {
return <FollowList follows={useFollowing(user.id)} />;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
'use client';
import FollowButton from '@/app/(menu)/(public)/[username]/_components/elements/FollowButton';
import UserIcon from '@/app/(menu)/(public)/[username]/_components/elements/UserIcon';
import { Box, Typography, styled } from '@mui/material';

const UnselectableCard = styled('div')`
border-bottom: 1px solid ${({ theme }) => theme.palette.grey[100]};
background-color: ${({ theme }) => theme.palette.background.paper};
color: rgba(0, 0, 0, 0.87);
`;

const Flex = styled(Box)`
display: flex;
flex-wrap: nowrap;
`;

const VFlex = styled(Flex)`
flex-direction: column;
width: 100%;
`;

const HFlex = styled(Flex)`
flex-direction: row;
`;

const HFlexS = styled(Flex)`
flex-direction: row;
justify-content: space-between;
`;

const FillFlex = styled(Box)`
flex-grow: 1;
`;

const DisplayName = styled(Typography)`
word-wrap: break-word;
font-weight: bold;
font-size: 20px;
`;

const ButtonArea = styled(Box)`
width: 100%;
text-align: right;
`;

const UserName = styled(Typography)`
color: #8899a6;
font-size: 15px;
`;

const Avater = styled(UserIcon)`
aspect-ratio: 1;
height: 64px;
width: 64px;
margin: 0 10px auto;

${({ theme }) => theme.breakpoints.down('desktop')} {
margin: 0 10px auto;
height: 64px;
width: 64px;
}
`;

const Bio = styled(Typography)`
white-space: pre-wrap;
margin-bottom: 12px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
`;

type Props = {
id: number;
name: string;
username: string;
profileImageUrl: string;
bio: string;
};

export default function FFProfileCard({
name,
username,
profileImageUrl,
bio,
id,
}: Props) {
return (
<UnselectableCard>
<HFlex>
<Avater src={profileImageUrl} alt={'プロフィール画像'} />
<VFlex style={{ margin: '12px 0' }}>
<HFlexS>
<VFlex>
<DisplayName>{name}</DisplayName>
<UserName>@{username}</UserName>
</VFlex>
{/* フォローされてるか表示 */}
{/* <FollowedDisplay/> */}
<ButtonArea>
<FollowButton userId={id} />
</ButtonArea>
</HFlexS>
<FillFlex>
<Bio>{bio}</Bio>
</FillFlex>
</VFlex>
</HFlex>
</UnselectableCard>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { SWRInfiniteResponse } from 'swr/infinite';
import { FollowList } from '@cuculus/cuculus-api';
import { CircularProgress } from '@mui/material';
import FFProfileCard from '@/app/(menu)/(public)/[username]/_components/layouts/FFProfileCard';

type Props = {
follows: SWRInfiniteResponse<FollowList | undefined, Error>;
};

/**
* フォロー/フォロワーリスト
* @param follows
* @constructor
*/
export default function FollowList({ follows }: Props) {
const { data, isLoading, size, setSize } = follows;

if (isLoading) {
return (
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
<CircularProgress />
</div>
);
}

return (
<>
<div>現在のページ: {size}</div>
<button onClick={() => void setSize(size + 1)}>次のページへ</button>
{data?.map((follows, index) => (
<div key={index}>
{follows?.users.map((User, number) => (
<FFProfileCard
key={number}
name={User.name}
username={User.username}
bio={User.bio}
profileImageUrl={User.profileImageUrl}
id={User.id}
/>
))}
</div>
))}
</>
);
}
36 changes: 33 additions & 3 deletions src/app/(menu)/(public)/[username]/followers/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,40 @@
import ComingSoon from '@/app/(menu)/_components/main/ComingSoon';
import PrimaryColumn from '@/app/(menu)/_components/main/PrimaryColumn';
import { cache } from 'react';
import { usersApi } from '@/libs/cuculus-client';
import { notFound } from 'next/navigation';
import Following from '@/app/(menu)/(public)/[username]/_components/Following';

type Params = { params: { username: string } };

const getUser = cache(async (username: string) => {
try {
return await usersApi.getUserByUsername(
{ username },
{
next: {
revalidate: 300,
},
},
);
} catch {
return undefined;
}
});

/**
* フォロワー一覧ページ
* @param params
*/
export default async function page({ params }: Params) {
const username = decodeURIComponent(params.username);
const user = await getUser(username);
if (!user) {
notFound();
}

export default function page({}: { params: { userName: string } }) {
return (
<PrimaryColumn hideHeader={true}>
<ComingSoon />
{/* <Following user={user} /> */}
</PrimaryColumn>
);
}
36 changes: 33 additions & 3 deletions src/app/(menu)/(public)/[username]/following/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,40 @@
import ComingSoon from '@/app/(menu)/_components/main/ComingSoon';
import PrimaryColumn from '@/app/(menu)/_components/main/PrimaryColumn';
import { cache } from 'react';
import { usersApi } from '@/libs/cuculus-client';
import { notFound } from 'next/navigation';
import Following from '@/app/(menu)/(public)/[username]/_components/Following';

type Params = { params: { username: string } };

const getUser = cache(async (username: string) => {
try {
return await usersApi.getUserByUsername(
{ username },
{
next: {
revalidate: 300,
},
},
);
} catch {
return undefined;
}
});

/**
* フォロー一覧ページ
* @param params
*/
export default async function page({ params }: Params) {
const username = decodeURIComponent(params.username);
const user = await getUser(username);
if (!user) {
notFound();
}

export default function page({}: { params: { userName: string } }) {
return (
<PrimaryColumn hideHeader={true}>
<ComingSoon />
<Following user={user} />
</PrimaryColumn>
);
}
53 changes: 53 additions & 0 deletions src/swr/client/follows.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { useAuth } from '@/swr/client/auth';
import { usersApi } from '@/libs/cuculus-client';
import { getAuthorizationHeader } from '@/libs/auth';
import useSWRInfinite from 'swr/infinite';
import { FollowList } from '@cuculus/cuculus-api';

// FIXME 確認用に一旦10件にしている
const LIMIT = 10;

type SWRKey = {
key: string;
authId?: number;
userId: number;
nextUntil?: Date;
};

/**
* フォロー一覧の取得
* @param userId
*/
export const useFollowing = (userId: number) => {
const { data: authId } = useAuth();
return useSWRInfinite<
FollowList | undefined,
Error,
(index: number, prev: FollowList | undefined) => SWRKey | null
>(
(index, previousPageData) => {
// 取得結果が空の場合は次のページがないと判断して終了
if (previousPageData && !previousPageData.users.length) {
return null;
}
return {
key: 'useFollowing',
authId,
userId,
nextUntil: previousPageData?.nextUntil,
};
},
async (args) => {
try {
return await usersApi.getUserFollowing(
{ id: args.userId, until: args.nextUntil, limit: LIMIT },
{
headers: await getAuthorizationHeader(authId),
},
);
} catch (error) {
throw error;
}
},
);
};