Skip to content
This repository has been archived by the owner on Dec 16, 2024. It is now read-only.

Commit

Permalink
feat: implements roster profile-image upload service
Browse files Browse the repository at this point in the history
  • Loading branch information
jspark2000 committed Mar 25, 2024
1 parent 75cf78e commit 188a0eb
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 15 deletions.
18 changes: 17 additions & 1 deletion backend/app/src/attendance/attendance.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
UnexpectedException
} from '@libs/exception'
import { PrismaService } from '@libs/prisma'
import { calculatePaginationOffset } from '@libs/utils'
import { calculatePaginationOffset, formatFileUrl } from '@libs/utils'
import {
Prisma,
RosterType,
Expand Down Expand Up @@ -87,6 +87,14 @@ export class AttendanceService {
]
})

attendances.forEach((attendance) => {
if (attendance.Roster.profileImageUrl) {
attendance.Roster.profileImageUrl = formatFileUrl(
attendance.Roster.profileImageUrl
)
}
})

const total = await this.prisma.attendance.count({
where: {
scheduleId,
Expand Down Expand Up @@ -157,6 +165,14 @@ export class AttendanceService {
]
})

attendances.forEach((attendance) => {
if (attendance.Roster.profileImageUrl) {
attendance.Roster.profileImageUrl = formatFileUrl(
attendance.Roster.profileImageUrl
)
}
})

const total = await this.prisma.attendance.count({
where: {
scheduleId,
Expand Down
24 changes: 21 additions & 3 deletions backend/app/src/roster/roster.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
} from '@libs/exception'
import { PrismaService } from '@libs/prisma'
import { StorageService } from '@libs/storage'
import { calculatePaginationOffset } from '@libs/utils'
import { calculatePaginationOffset, formatFileUrl } from '@libs/utils'
import { Prisma, RosterStatus, type Roster } from '@prisma/client'
import type { CreateRosterDTO, UpdateRosterDTO } from './dto/roster.dto'

Expand All @@ -22,11 +22,17 @@ export class RosterService {

async getRoster(rosterId: number): Promise<Roster> {
try {
return await this.prisma.roster.findUniqueOrThrow({
const roster = await this.prisma.roster.findUniqueOrThrow({
where: {
id: rosterId
}
})

if (roster.profileImageUrl) {
roster.profileImageUrl = formatFileUrl(roster.profileImageUrl)
}

return roster
} catch (error) {
if (
error instanceof Prisma.PrismaClientKnownRequestError &&
Expand All @@ -40,11 +46,17 @@ export class RosterService {

async getRosterByStudentId(studentId: string): Promise<Roster> {
try {
return await this.prisma.roster.findUniqueOrThrow({
const roster = await this.prisma.roster.findUniqueOrThrow({
where: {
studentId
}
})

if (roster.profileImageUrl) {
roster.profileImageUrl = formatFileUrl(roster.profileImageUrl)
}

return roster
} catch (error) {
if (
error instanceof Prisma.PrismaClientKnownRequestError &&
Expand Down Expand Up @@ -80,6 +92,12 @@ export class RosterService {
]
})

rosters.forEach((roster) => {
if (roster.profileImageUrl) {
roster.profileImageUrl = formatFileUrl(roster.profileImageUrl)
}
})

const total = await this.prisma.roster.count({
where: {
status
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client'

import { ImageInput } from '@/components/ImageInput'
import { Button } from '@/components/ui/button'
import {
Form,
Expand Down Expand Up @@ -30,6 +31,11 @@ import type { z } from 'zod'

export default function UpdateRosterForm({ roster }: { roster: Roster }) {
const [isFetching, setIsFetching] = useState(false)
const [selectedFile, setSelectedFile] = useState<File | null>(null)

const handleFileSelect = (file: File) => {
setSelectedFile(file)
}

const router = useRouter()

Expand All @@ -39,9 +45,18 @@ export default function UpdateRosterForm({ roster }: { roster: Roster }) {
resolver: zodResolver(UpdateRosterFormSchema),
defaultValues: {
...roster,
offPosition: roster.offPosition ?? undefined,
defPosition: roster.defPosition ?? undefined,
splPosition: roster.splPosition ?? undefined
offPosition:
roster.type === RosterType.Athlete
? roster.offPosition ?? undefined
: undefined,
defPosition:
roster.type === RosterType.Athlete
? roster.defPosition ?? undefined
: undefined,
splPosition:
roster.type === RosterType.Athlete
? roster.splPosition ?? undefined
: undefined
}
})

Expand All @@ -58,6 +73,17 @@ export default function UpdateRosterForm({ roster }: { roster: Roster }) {
},
false
)

if (selectedFile) {
const formData = new FormData()
formData.append('image', selectedFile)
await fetcher.put(
`/rosters/${roster.id}/profile-image`,
formData,
false
)
}

router.push('/console/roster?revalidate=true')
router.refresh()
toast.success('부원정보가 업데이트 되었습니다')
Expand All @@ -74,6 +100,12 @@ export default function UpdateRosterForm({ roster }: { roster: Roster }) {
onSubmit={form.handleSubmit(onSubmit)}
className="grid grid-cols-12 gap-5"
>
<div className="col-span-12">
<p className="text-sm font-medium leading-6 peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
프로필 이미지 변경
</p>
<ImageInput onFileSelect={handleFileSelect} />
</div>
<div className="col-span-12 sm:col-span-6 lg:col-span-4">
<FormField
control={form.control}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,14 @@ export default function RosterListTable({

return (
<div className="flex flex-nowrap items-center gap-x-1.5">
<div className="h-6 w-6 rounded-full">
<div className="h-6 w-6">
{roster.profileImageUrl ? (
<Image
src={roster.profileImageUrl}
width={32}
height={32}
alt=""
className="object-cover"
className="h-full w-full rounded-full object-cover"
/>
) : (
<UserIcon />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,14 @@ export default function AttendanceListTable({
const attendance = row.original

return (
<div className="flex flex-nowrap gap-x-1">
<div className="flex flex-nowrap items-center gap-x-1">
{attendance.Roster.profileImageUrl ? (
<Image
src={attendance.Roster.profileImageUrl}
width={128}
height={128}
alt="profile"
className="h-6 w-6 object-cover"
className="h-6 w-6 rounded-full object-cover"
/>
) : (
<UserIcon className="h-6 w-6 object-cover" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,20 @@ export default function AttendanceCheckCard({

return (
<section className="flex aspect-square flex-col items-center justify-center p-0">
<div className="relative isolate flex w-full flex-col justify-end overflow-hidden rounded-2xl bg-gray-900 px-8 pb-8 pt-64">
<div className="relative isolate flex w-full flex-col justify-end overflow-hidden rounded-2xl bg-gray-800 px-8 pb-8 pt-64">
{attendance.Roster.profileImageUrl ? (
<Image
src={attendance.Roster.profileImageUrl}
width={480}
height={640}
alt="image"
className="absolute inset-0 -z-10 h-3/5 w-full object-cover"
className="absolute inset-0 -z-10 h-4/5 w-full object-cover"
/>
) : (
<UserIcon className="absolute inset-0 -z-10 h-3/5 w-full object-cover text-white" />
<UserIcon className="absolute inset-0 -z-10 h-4/5 w-full object-cover text-white" />
)}
<div className="absolute inset-0 -z-10 bg-gradient-to-t from-black via-gray-900/80" />
<div className="absolute inset-0 -z-10 rounded-2xl ring-1 ring-inset ring-gray-900/40" />
<div className="absolute inset-0 -z-10 ring-0" />

<div className="flex flex-col space-y-3 text-white">
<span className="text-base font-semibold">
Expand Down

0 comments on commit 188a0eb

Please sign in to comment.