Skip to content
Merged
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
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,6 @@ jobs:
run: chmod +x gradlew

- name: Build (includes React build)
env:
CI: false
run: ./gradlew clean build --no-daemon
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,4 @@ src/main/resources/application-dev.yml

.env
*.tar
/.claude/
51 changes: 14 additions & 37 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.1'
id 'io.spring.dependency-management' version '1.1.4'
}

repositories {
Expand All @@ -23,12 +24,6 @@ dependencies {
implementation libs.org.mybatis.spring.boot.mybatis.spring.boot.starter
runtimeOnly libs.org.springframework.boot.spring.boot.devtools

// Test
testImplementation libs.org.junit.jupiter.junit.jupiter
testImplementation libs.org.mockito.mockito.junit.jupiter
testImplementation libs.org.assertj.assertj.core


// JPA
implementation libs.org.springframework.boot.spring.boot.starter.data.jpa

Expand Down Expand Up @@ -83,57 +78,38 @@ tasks.withType(Javadoc) {
options.encoding = 'UTF-8'
}

tasks.test {
useJUnitPlatform()
}

def frontendDir = "$projectDir/src/main/frontend"
def querydslDir = layout.buildDirectory.dir("generated/querydsl").get().asFile
def reactBuildDir = layout.buildDirectory.dir("frontend").get().asFile

sourceSets {
main {
java {
srcDir querydslDir
}
resources {
srcDirs = ["$projectDir/src/main/resources"]
}
}
}

// ✅ (추가) Q 클래스 생성 위치를 querydslDir로 고정
tasks.withType(JavaCompile).configureEach {
options.generatedSourceOutputDirectory = querydslDir
bootJar {
dependsOn "copyReactBuildFiles"
}

tasks.named("jar") {
dependsOn("copyReactBuildFiles")
from(reactBuildDir) {
into("static") // classpath:/static/ 로 들어감
}
processResources {
dependsOn "copyReactBuildFiles"
}

tasks.named("bootJar") {
dependsOn("copyReactBuildFiles")
from(reactBuildDir) {
into("static")
}
}

tasks.register('installReact', Exec) {
task installReact(type: Exec) {
workingDir "$frontendDir"
inputs.dir "$frontendDir"
group = BasePlugin.BUILD_GROUP
if (System.getProperty('os.name').toLowerCase(Locale.ROOT).contains('windows')) {
commandLine 'npm.cmd', 'ci'
commandLine "npm.cmd", "audit", "fix"
commandLine 'npm.cmd', 'install'
} else {
commandLine 'npm', 'ci'
commandLine "npm", "audit", "fix"
commandLine 'npm', 'install'
}
}

tasks.register('buildReact', Exec) {
environment "CI", "false"
task buildReact(type: Exec) {
dependsOn "installReact"
workingDir "$frontendDir"
inputs.dir "$frontendDir"
Expand All @@ -144,8 +120,9 @@ tasks.register('buildReact', Exec) {
commandLine "npm", "run-script", "build"
}
}
tasks.register('copyReactBuildFiles', Copy) {

task copyReactBuildFiles(type: Copy) {
dependsOn "buildReact"
from "$frontendDir/build"
into reactBuildDir
into "$buildDir/resources/main/static"
}
17 changes: 0 additions & 17 deletions src/main/frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

41 changes: 20 additions & 21 deletions src/main/frontend/src/App.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react';
import logo from './logo.svg';
import './App.css';
import {Helmet} from "react-helmet-async";
import ModalContainer from "./js/setup/modal/ModalContainer";
Expand All @@ -9,28 +8,28 @@ import {Route, Routes} from "react-router-dom";
import MainPage from "./js/components/MainPage";

function App() {
// 전역 툴팁 함수들 등록
React.useEffect(() => {
registerGlobalTooltip();
}, []);
// 전역 툴팁 함수들 등록
React.useEffect(() => {
registerGlobalTooltip();
}, []);

return (
<div className="App">
<Helmet>
<title>Baektracker</title>
<meta name='viewport' content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
</Helmet>
<ModalContainer/>
<TooltipContainer/>
<Routes>
<Route path='/'>
<Route path='' element={<MainPage/>}>
return (
<div className="App">
<Helmet>
<title>Baektracker</title>
<meta name='viewport' content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
</Helmet>
<ModalContainer/>
<TooltipContainer/>
<Routes>
<Route path='/'>
<Route path='' element={<MainPage/>}>

</Route>
</Route>
</Routes>
</div>
);
</Route>
</Route>
</Routes>
</div>
);
}

export default App;
18 changes: 17 additions & 1 deletion src/main/frontend/src/css/styles.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -485,8 +485,24 @@

.userProgressName .rating_text {
margin: 0 6px;
font-size: 14px;
font-size: 16px;
cursor: pointer;
}

.userProgressName .increase_icon {
margin-left: 4px;
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 10px solid #1e90ff; /* 파란색 */
}

.userProgressName .increased_rating_text {
margin: 0 3px 0 2px;
font-size: 13px;
cursor: pointer;
color: #484848;
}

.userProgressName .pass_text {
Expand Down
38 changes: 19 additions & 19 deletions src/main/frontend/src/js/components/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function Header({fromDate, toDate, setFromDate, setToDate}) {
})
}

const setWeekDates = (date: Date) => {
const setWeekDates = (date) => {
const fd = DateUtils.getFirstDateOfWeek(date);
const td = DateUtils.getLastDateOfWeek(date);
setFromDate(DateUtils.dateToStringYYMMdd(fd))
Expand Down Expand Up @@ -93,21 +93,21 @@ export function Header({fromDate, toDate, setFromDate, setToDate}) {
)
}

// FineInfo 컴포넌트
const FineInfo = ({totalFine, onShowReceipt, className}) => {
const formatCurrency = (amount) => {
return new Intl.NumberFormat("ko-KR").format(amount)
}

return (
<div className={`${styles.fineInfoContainer} ${className || ""}`}>
<div className={styles.fineInfoAmount}>
<span className={styles.fineInfoLabel}>누적 벌금</span>
<span className={styles.fineInfoAmountText}>₩{formatCurrency(totalFine)}</span>
</div>
<button className={styles.fineInfoReceiptButton} onClick={onShowReceipt}>
영수증 보기
</button>
</div>
)
}
// // FineInfo 컴포넌트
// const FineInfo = ({totalFine, onShowReceipt, className}) => {
// const formatCurrency = (amount) => {
// return new Intl.NumberFormat("ko-KR").format(amount)
// }
//
// return (
// <div className={`${styles.fineInfoContainer} ${className || ""}`}>
// <div className={styles.fineInfoAmount}>
// <span className={styles.fineInfoLabel}>누적 벌금</span>
// <span className={styles.fineInfoAmountText}>₩{formatCurrency(totalFine)}</span>
// </div>
// <button className={styles.fineInfoReceiptButton} onClick={onShowReceipt}>
// 영수증 보기
// </button>
// </div>
// )
// }
4 changes: 2 additions & 2 deletions src/main/frontend/src/js/components/MarkedProblemItem.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export function MarkedProblemItem({problem, index}) {
window.open(`https://www.acmicpc.net/problem/${problem.problemId}`, "_blank")
}}
className={cm(`${styles.userProgressProblemItem} ${problem.solved ? styles.userProgressSolved : styles.userProgressUnsolved}`,
`${problem.is_shared_problem == 1 && styles.is_shared_problem}`)}
`${problem.is_shared_problem === 1 && styles.is_shared_problem}`)}
onMouseEnter={tooltip.onMouseEnter}
onMouseLeave={tooltip.onMouseLeave}
>
Expand All @@ -44,4 +44,4 @@ export function MarkedProblemItem({problem, index}) {
</div>
</div>
)
}
}
14 changes: 13 additions & 1 deletion src/main/frontend/src/js/components/UserProgress.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ export function UserProgress({fromDate, toDate}) {
const threeDotsRefs = useRef({})
const longPressTimer = useRef(null)

// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => {
getAllUsers()
initLoad();
}, []);

// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => {
getWeeklyUsersProgress();
}, [fromDate, toDate]);
Expand Down Expand Up @@ -248,6 +250,7 @@ export function UserProgress({fromDate, toDate}) {
const userProgress = problems[user.id];
const score = userProgress ? userProgress.score : 0;
const isWeekPass = userProgress?.isWeekPass ?? false
const increasedRating = userProgress.increasedRating > 0 ? userProgress.increasedRating : null;

const problemList = userProgress?.problems;
return (
Expand All @@ -266,7 +269,16 @@ export function UserProgress({fromDate, toDate}) {
<span className={styles.rating_text} style={{
color: DesignUtils.getRatingColor(user.level)
}} onMouseEnter={tooltip.onMouseEnter}
onMouseLeave={tooltip.onMouseLeave}>{user.rating}</span>
onMouseLeave={tooltip.onMouseLeave}>{user.rating}
{
increasedRating && <>
<span className={styles.increase_icon}></span>
<span
className={styles.increased_rating_text}>{increasedRating}</span>
</>
}

</span>
{isWeekPass ?
<span className={styles.pass_text}>PASS</span> : ''}
</span>
Expand Down
3 changes: 2 additions & 1 deletion src/main/frontend/src/js/components/WeekProblems.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export function WeekProblems({fromDate, toDate}) {

const [weeklyProblemInputs, setWeeklyProblemInputs] = useState([-1, -1, -1])

// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => {
getWeeklyProblems();
}, [fromDate, toDate]);
Expand Down Expand Up @@ -112,4 +113,4 @@ export function WeekProblems({fromDate, toDate}) {
</section>

)
}
}
2 changes: 2 additions & 0 deletions src/main/frontend/src/js/modal/FineReceiptModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ export function FineReceiptModal(props) {
const [totalSum, setTotalSum] = useState(0)
const [fold, setFold] = useState(true)

// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => {
getTotalFine()
}, []);

// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => {
getMonthFine()
// getWeeklyResult();
Expand Down
15 changes: 9 additions & 6 deletions src/main/frontend/src/js/modal/LayerModal.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,26 @@ import {ScrollUtils} from "../utils/ScrollUtils";
Usage
ex) <LayerModal {...props} maxWidth={1045} top={45}>
*/
export const LayerModal = ({modalRef, scrollable, children, top, left, width, backgroundColor,
height, windowBlocked, minWidth, maxWidth, minHeight, maxHeight, paddingBottom}) => {
export const LayerModal = ({
modalRef, scrollable, children, top, left, width, backgroundColor,
height, windowBlocked, minWidth, maxWidth, minHeight, maxHeight, paddingBottom
}) => {
const [fadeIn, setFadeIn] = useState(false);

const scrollRef = useRef(null)

// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() => {
let prevScrollY = null;
if(!scrollable){
if (!scrollable) {
prevScrollY = ScrollUtils.preventScroll(scrollRef.current.body);
}
const timer = setTimeout(() => {
setFadeIn(true)
}, 100)

return () => {
if(prevScrollY){
if (prevScrollY) {
ScrollUtils.allowScroll(scrollRef.current.body, prevScrollY)
}
prevScrollY = null;
Expand All @@ -34,10 +37,10 @@ export const LayerModal = ({modalRef, scrollable, children, top, left, width, ba

useEffect(() => {
let prevScrollY = null;
if(windowBlocked){
if (windowBlocked) {
prevScrollY = ScrollUtils.preventScroll(document.body);
}
return ()=>{
return () => {
ScrollUtils.allowScroll(document.body, prevScrollY)
}
}, []);
Expand Down
Loading
Loading