Skip to content

Commit

Permalink
feat: 필터링 기능 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
jellyyelly committed Oct 24, 2024
1 parent ee2a2fb commit 40d6f07
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 31 deletions.
54 changes: 44 additions & 10 deletions src/routes/messages/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script>
import { onDestroy, onMount } from "svelte";
import { get } from 'svelte/store';
import { letters } from '../../stores/letter.js';
import { letters, searchTerm, filteredLetters, searchField } from '../../stores/letter.js';
import LetterItem from '../../components/LetterItem.svelte';
import EmptyItem from '../../components/EmptyItem.svelte';
import LetterTableHeader from '../../components/LetterTableHeader.svelte';
Expand All @@ -11,14 +11,19 @@
let endPage = 1;
const view = 5;
const searchOptions = [
{ value: 'all', label: '전체' },
{ value: 'uuid', label: 'uuid' },
{ value: 'username', label: '작성자' },
{ value: 'content', label: '편지 내용' },
{ value: 'message_f', label: 'F 유형 답장' },
{ value: 'message_t', label: 'T 유형 답장' },
{ value: 'createdAt', label: '작성 시간' },
];
onMount(() => {
letters.resetLetters();
letters.fetchLetters().then(() => {
console.log('편지 목록: ', get(letters).list)
console.log('현재 페이지: ', get(letters).pageNumber)
console.log('전체 개수: ', get(letters).totalElements)
console.log('전체 페이지 개수: ', get(letters).totalPages)
console.log('마지막 페이지?: ', get(letters).last)
updatePagination();
})
});
Expand All @@ -28,7 +33,6 @@
$: totalPages = $letters.totalPages;
const goToPage = (page) => {
console.log('이동하려는 페이지= ', page)
if (page >= 0 && page < totalPages) {
currentPage = page;
Expand All @@ -51,15 +55,29 @@

<!-- 테이블 -->
<div class="letter-table">
<div class="table-statistics">
전체 편지 개수: {$letters.totalElements}

<!-- 테이블 필터 -->
<div class="filter-container">
<label class="flex px-2" for="user-filter">
필터 조회 수: {$filteredLetters.length}
</label>
<div class="flex gap-2">
<select id="user-filter" bind:value={$searchField} class="filter-select">
{#each searchOptions as option }
<option value={option.value}>{option.label}</option>
{/each}
</select>
<div>
<input id="filter" type="text" class="filter-input-field" bind:value={$searchTerm} autocomplete="nickname" placeholder="필터링 할 단어를 입력하세요." />
</div>
</div>
</div>

<!-- 테이블 헤더 -->
<LetterTableHeader />

<!-- 테이블 리스트 -->
{#each reactiveData as letter, index}
{#each $filteredLetters as letter, index}
<LetterItem {letter} />
{:else}
<EmptyItem />
Expand Down Expand Up @@ -87,4 +105,20 @@
.letter-table {
@apply flex flex-col mx-10 my-6 px-2 py-2 rounded-md flex-nowrap text-nowrap
}
.filter-container {
@apply flex flex-col gap-2 mb-2.5 px-1.5 py-2.5 min-w-[385px] max-w-[400px] justify-start items-start border border-neutral-300 rounded-xl flex-nowrap text-nowrap
}
.filter-container:focus-within {
@apply outline outline-2 outline-neutral-500
}
.filter-select {
@apply min-w-[80px] pl-2 py-2 rounded-lg bg-neutral-200/50
}
.filter-input-field {
@apply min-w-[280px] rounded-lg px-2.5 py-2 bg-neutral-200/50 focus:bg-white focus:outline outline-2 outline-neutral-500
}
</style>
60 changes: 47 additions & 13 deletions src/routes/users/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,34 +1,39 @@
<script>
import { onMount } from "svelte";
import { get } from 'svelte/store';
import { users } from '../../stores/user.js';
import { users, searchTerm, filteredUsers, searchField } from '../../stores/user.js';
import UserItem from '../../components/UserItem.svelte';
import EmptyItem from '../../components/EmptyItem.svelte';
import UserTableHeader from "../../components/UserTableHeader.svelte";
import Navigation from "../../components/Navigation.svelte";
let startPage = 0;
let endPage = 1;
const view = 3;
const view = 5;
const searchOptions = [
{ value: 'all', label: '전체' },
{ value: 'uuid', label: 'uuid' },
{ value: 'nickname', label: '닉네임' },
{ value: 'email', label: '이메일' },
{ value: 'preference', label: '선호 유형' },
{ value: 'createdAt', label: '가입일' },
{ value: 'dormant', label: '휴면 여부' },
{ value: 'dormantAt', label: '휴면일' },
];
onMount(() => {
users.resetUsers();
users.fetchUsers().then(() => {
console.log('유저 목록: ', get(users).list)
console.log('현재 페이지: ', get(users).pageNumber)
console.log('전체 개수: ', get(users).totalElements)
console.log('전체 페이지 개수: ', get(users).totalPages)
console.log('마지막 페이지?: ', get(users).last)
updatePagination();
})
});
$: reactiveData = $users.list;
// $: reactiveData = $users.list;
$: currentPage = $users.pageNumber;
$: totalPages = $users.totalPages;
const goToPage = (page) => {
console.log('이동하려는 페이지= ', page)
if (page >= 0 && page < totalPages) {
currentPage = page;
Expand All @@ -51,16 +56,29 @@

<!-- 테이블 -->
<div class="users-table">
<!-- 통계 -->
<div class="table-statistics">
전체 유저 수: {$users.totalElements}

<!-- 테이블 필터 -->
<div class="filter-container">
<label class="flex px-2" for="user-filter">
필터 조회 수: {$filteredUsers.length}
</label>
<div class="flex gap-2">
<select id="user-filter" bind:value={$searchField} class="filter-select">
{#each searchOptions as option }
<option value={option.value}>{option.label}</option>
{/each}
</select>
<div>
<input id="filter" type="text" class="filter-input-field" bind:value={$searchTerm} autocomplete="nickname" placeholder="필터링 할 단어를 입력하세요." />
</div>
</div>
</div>

<!-- 테이블 헤더 -->
<UserTableHeader />

<!-- 테이블 리스트 -->
{#each reactiveData as user, index}
{#each $filteredUsers as user, index}
<UserItem {user} />
{:else}
<EmptyItem />
Expand Down Expand Up @@ -88,4 +106,20 @@
.users-table {
@apply flex flex-col mx-10 mb-6 px-2 py-2 rounded-md flex-nowrap
}
.filter-container {
@apply flex flex-col gap-2 mb-2.5 px-1.5 py-2.5 min-w-[385px] max-w-[390px] justify-start items-start border border-neutral-300 rounded-xl flex-nowrap text-nowrap
}
.filter-container:focus-within {
@apply outline outline-2 outline-neutral-500
}
.filter-select {
@apply min-w-[80px] pl-2 py-2 rounded-lg bg-neutral-200/50
}
.filter-input-field {
@apply min-w-[280px] rounded-lg px-2.5 py-2 bg-neutral-200/50 focus:bg-white focus:outline outline-2 outline-neutral-500
}
</style>
55 changes: 52 additions & 3 deletions src/stores/letter.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { get, writable } from "svelte/store";
import { get, writable, derived } from "svelte/store";
import { getApi, delApi } from "./api.js";

// 검색어를 저장할 store 생성
export const searchTerm = writable("");
export const searchField = writable("all"); // 기본값은 전체 검색

function setLetters() {
let initValues = {
list: [
Expand Down Expand Up @@ -33,7 +37,7 @@ function setLetters() {

const getData = await getApi(options);

console.log('data: ', getData)
// console.log('data: ', getData)

const newData = {
list: getData.data.content,
Expand Down Expand Up @@ -71,4 +75,49 @@ function setLetters() {
}
}

export const letters = setLetters()
export const letters = setLetters();

// 안전한 문자열 검사 함수
const safeIncludes = (field, searchTerm) => {
// field가 null 또는 undefined면 false 반환
if (field == null) return false;

// 숫자인 경우 문자열로 변환
const fieldStr = String(field).toLowerCase();
return fieldStr.includes(searchTerm.toLowerCase());
};

// 필터링된 사용자 목록을 생성하는 derived store
export const filteredLetters = derived(
[letters, searchTerm, searchField],
([$letters, $searchTerm, $searchField]) => {
if (!$searchTerm) return $letters.list;

return $letters.list.filter(letter => {
switch ($searchField) {
case 'username':
return safeIncludes(letter.username, $searchTerm);
case 'content':
return safeIncludes(letter.content, $searchTerm);
case 'uuid':
return safeIncludes(letter.replyId, $searchTerm);
case 'message_t':
return safeIncludes(letter.reply.message_t, $searchTerm);
case 'message_f':
return safeIncludes(letter.reply.message_f, $searchTerm);
case 'createdAt':
return safeIncludes(letter.createdAt, $searchTerm);
case 'all':
default:
return (
safeIncludes(letter.username, $searchTerm) ||
safeIncludes(letter.content, $searchTerm) ||
safeIncludes(letter.replyId, $searchTerm) ||
safeIncludes(letter.message_t, $searchTerm) ||
safeIncludes(letter.message_f, $searchTerm) ||
safeIncludes(letter.createdAt, $searchTerm)
);
}
});
}
);
60 changes: 55 additions & 5 deletions src/stores/user.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { get, writable } from "svelte/store";
import { get, writable, derived } from "svelte/store";
import { getApi, delApi } from "./api.js";

// 검색어를 저장할 store 생성
export const searchTerm = writable("");
export const searchField = writable("all"); // 기본값은 전체 검색

function setUsers() {
let initValues = {
list: [
Expand Down Expand Up @@ -29,7 +33,7 @@ function setUsers() {

const getData = await getApi(options);

console.log('data: ', getData)
// console.log('data: ', getData)

const newData = {
list: getData.data.content,
Expand Down Expand Up @@ -64,8 +68,6 @@ function setUsers() {

const getData = await getApi(options);

console.log('data: ', getData)

remaining = getData.data.remaining;
}
catch(error) {
Expand All @@ -87,4 +89,52 @@ function setUsers() {
}
}

export const users = setUsers()
export const users = setUsers();

// 안전한 문자열 검사 함수
const safeIncludes = (field, searchTerm) => {
// field가 null 또는 undefined면 false 반환
if (field == null) return false;

// 숫자인 경우 문자열로 변환
const fieldStr = String(field).toLowerCase();
return fieldStr.includes(searchTerm.toLowerCase());
};

// 필터링된 사용자 목록을 생성하는 derived store
export const filteredUsers = derived(
[users, searchTerm, searchField],
([$users, $searchTerm, $searchField]) => {
if (!$searchTerm) return $users.list;

return $users.list.filter(user => {
switch ($searchField) {
case 'nickname':
return safeIncludes(user.nickname, $searchTerm);
case 'email':
return safeIncludes(user.email, $searchTerm);
case 'uuid':
return safeIncludes(user.userId, $searchTerm);
case 'preference':
return safeIncludes(user.preference, $searchTerm);
case 'createdAt':
return safeIncludes(user.createdAt, $searchTerm);
case 'dormant':
return safeIncludes(user.dormant, $searchTerm);
case 'dormantAt':
return safeIncludes(user.dormantAt, $searchTerm);
case 'all':
default:
return (
safeIncludes(user.nickname, $searchTerm) ||
safeIncludes(user.email, $searchTerm) ||
safeIncludes(user.userId, $searchTerm) ||
safeIncludes(user.preference, $searchTerm) ||
safeIncludes(user.createdAt, $searchTerm) ||
safeIncludes(user.dormant, $searchTerm) ||
safeIncludes(user.dormantAt, $searchTerm)
);
}
});
}
);

0 comments on commit 40d6f07

Please sign in to comment.