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
6 changes: 2 additions & 4 deletions src/category/category.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,23 +75,21 @@ export const getCategoryListService = async ({ userId }) => {
});

categories = await listUserCategories({ userId });
}

// 기본 UserCategory 생성 후, 각 카테고리별 Word를 UserWord로 복사
// 기본 UserCategory 생성 직후에만 복사
const wordsRepo = (await import("../words/repositories/words.repository.js")).default;
for (const userCategory of categories.filter(c => c.isDefault)) {
// 기본 카테고리 이름으로 Category 찾기
const category = await prisma.category.findFirst({
where: {
categoryName: userCategory.categoryName,
isDefault: true
}
});
if (category) {
// 해당 Category의 Word를 UserWord로 복사
await wordsRepo.createSnapshotFromWords(userId, userCategory.id);
}
}
}

return Promise.all(
categories.map(async (c) => {
Expand Down
2 changes: 2 additions & 0 deletions src/words/controllers/words.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export class WordsController {
async getWords(req, res, next) {
try {
const userId = req.user?.userId;
const accountType = req.user?.accountType;

const queryDto = new GetWordsQueryDto({
categoryId: req.query.categoryId,
Expand All @@ -19,6 +20,7 @@ export class WordsController {

const result = await wordsService.getWords(
userId,
accountType,
queryDto.categoryId,
queryDto.onlyFavorite
);
Expand Down
7 changes: 4 additions & 3 deletions src/words/routes/words.route.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ const router = express.Router();
* get:
* summary: 낱말 카드 조회
* description: |
* 낱말 카드 목록을 조회합니다.
* 토큰이 있으면 사용자별 낱말(즐겨찾기/개인화 포함), 없으면 기본 낱말만 반환합니다.
* categoryId가 있으면 data.category(카테고리 이름)도 함께 반환됩니다.
* 낱말 카드 목록을 조회합니다.
* 토큰이 있으면 게스트/소셜 계정 모두 사용자별 낱말(즐겨찾기/개인화 포함)을 조회합니다.
* 토큰이 없으면 기본 낱말만 반환합니다.
* categoryId가 있으면 data.category(카테고리 이름)도 함께 반환됩니다.
* tags: [Words]
* parameters:
* - in: query
Expand Down
40 changes: 19 additions & 21 deletions src/words/services/words.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ export class WordsService {
/**
* 내부용: 전체 낱말 카드 목록 생성 (categoryId 없이)
*/
async _getAllWordCards(userId, onlyFavorite = false) {
async _getAllWordCards(userId, accountType, onlyFavorite = false) {
const wordCards = [];
let categoryNameToUserCategoryIdMap = new Map();
let categoryNameToCategoryIdMap = new Map();
let hasUserCategories = false;

if (userId) {
if (userId && accountType !== 'GUEST') {
const userCategories = await wordsRepository.findAllUserCategories(userId);
if (userCategories.length > 0) {
hasUserCategories = true;
Expand Down Expand Up @@ -44,17 +44,14 @@ export class WordsService {
});
}

// 소셜 로그인(유저가 존재) 시에는 기본 Word를 반환하지 않고 UserWord만 반환
// 게스트(유저 없음)일 때만 기본 Word 반환
if (!onlyFavorite && !userId) {
const words = await wordsRepository.findWords(null, userId);
// 소셜/게스트 로그인(유저가 존재) 시에는 UserWord 기반, 비회원(토큰 없음)만 기본 Word 반환
if (!onlyFavorite && !userId && !accountType) {
const words = await wordsRepository.findWords();
words.forEach((word, index) => {
const wordCategoryName = word.category?.categoryName;
let mappedCategoryId = categoryNameToCategoryIdMap.get(wordCategoryName) || word.categoryId;
wordCards.push(new WordCardResponseDto({
cardId: word.id,
categoryId: mappedCategoryId,
categoryName: wordCategoryName,
categoryId: word.categoryId,
categoryName: word.category?.categoryName,
partOfSpeech: word.partOfSpeech,
word: word.word,
imageUrl: word.imageUrl,
Expand Down Expand Up @@ -101,20 +98,20 @@ export class WordsService {
/**
* 다음 displayOrder 계산 (기본 Word + UserWord 모두 고려)
* @param {string} userId
* @param {string} accountType
* @param {string} categoryId
* @returns {Promise<number>}
*/
async getNextDisplayOrder(userId, categoryId) {
async getNextDisplayOrder(userId, accountType, categoryId) {
// 1. UserWord 조회 (삭제된 것 제외)
const userWords = await wordsRepository.findUserWords(userId, categoryId, false, false);

// 2. UserWord가 있으면 최대값 + 1 반환
if (userWords.length > 0) {
const maxOrder = Math.max(...userWords.map(w => w.displayOrder));
return maxOrder + 1;
if (accountType !== 'GUEST') {
const userWords = await wordsRepository.findUserWords(userId, categoryId, false, false);
if (userWords.length > 0) {
const maxOrder = Math.max(...userWords.map(w => w.displayOrder));
return maxOrder + 1;
}
}

// 3. UserWord가 없으면 기본 Word 개수 반환
// 게스트이거나 UserWord가 없으면 기본 Word 개수 반환
const words = await wordsRepository.findWords(categoryId, userId);
return words.length;
}
Expand All @@ -124,13 +121,14 @@ export class WordsService {
* 기본 낱말(Word) + 개인 낱말(UserWord) 통합 반환
*
* @param {string} userId
* @param {string} accountType
* @param {string|null} categoryId - Category.id 또는 UserCategory.id
* @param {boolean} onlyFavorite
* @returns {Promise<Object>} { category, words }
*/
async getWords(userId, categoryId = null, onlyFavorite = false) {
async getWords(userId, accountType, categoryId = null, onlyFavorite = false) {
// 1. 전체 낱말 목록 생성 (categoryId 없이)
const allWords = await this._getAllWordCards(userId, onlyFavorite);
const allWords = await this._getAllWordCards(userId, accountType, onlyFavorite);

// 2. categoryId가 없으면 전체 반환
if (!categoryId) {
Expand Down