feat: 시즌별 마케팅 + 공지사항 관리 기능 추가
- 연간 세무 캘린더(7개 시즌) 기반 자동 Hero 섹션 전환 - 시즌 감지 시 D-Day 카운트다운, 긴박감 배지, 시즌 CTA 표시 - 서비스 카드 순서 시즌 관련 항목 우선 정렬 - 어드민 공지사항 CRUD (등록·수정·삭제, 기간·유형 설정) - 홈페이지 상단 공지 배너 자동 노출 (일반/배너/긴급) - CLAUDE.md에 세무 캘린더 및 마케팅 방향 하네스 추가 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
namespace TaxBaik.Infrastructure.Repositories;
|
||||
|
||||
using Dapper;
|
||||
using TaxBaik.Domain.Entities;
|
||||
using TaxBaik.Domain.Interfaces;
|
||||
|
||||
public class AnnouncementRepository(IDbConnectionFactory connectionFactory)
|
||||
: BaseRepository(connectionFactory), IAnnouncementRepository
|
||||
{
|
||||
private const string SelectColumns =
|
||||
"id, title, content, display_type, is_active, starts_at, ends_at, sort_order, created_at, updated_at";
|
||||
|
||||
public async Task<IEnumerable<Announcement>> GetActiveAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var conn = Conn();
|
||||
return await conn.QueryAsync<Announcement>(
|
||||
$@"SELECT {SelectColumns}
|
||||
FROM announcements
|
||||
WHERE is_active = TRUE
|
||||
AND (starts_at IS NULL OR starts_at <= NOW())
|
||||
AND (ends_at IS NULL OR ends_at >= NOW())
|
||||
ORDER BY sort_order DESC, created_at DESC");
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<Announcement>> GetAllAsync(CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var conn = Conn();
|
||||
return await conn.QueryAsync<Announcement>(
|
||||
$"SELECT {SelectColumns} FROM announcements ORDER BY sort_order DESC, created_at DESC");
|
||||
}
|
||||
|
||||
public async Task<Announcement?> GetByIdAsync(int id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var conn = Conn();
|
||||
return await conn.QueryFirstOrDefaultAsync<Announcement>(
|
||||
$"SELECT {SelectColumns} FROM announcements WHERE id = @Id",
|
||||
new { Id = id });
|
||||
}
|
||||
|
||||
public async Task<int> CreateAsync(Announcement announcement, CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var conn = Conn();
|
||||
return await conn.QueryFirstAsync<int>(
|
||||
@"INSERT INTO announcements
|
||||
(title, content, display_type, is_active, starts_at, ends_at, sort_order, created_at, updated_at)
|
||||
VALUES
|
||||
(@Title, @Content, @DisplayType, @IsActive, @StartsAt, @EndsAt, @SortOrder, NOW(), NOW())
|
||||
RETURNING id",
|
||||
announcement);
|
||||
}
|
||||
|
||||
public async Task UpdateAsync(Announcement announcement, CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var conn = Conn();
|
||||
await conn.ExecuteAsync(
|
||||
@"UPDATE announcements
|
||||
SET title = @Title,
|
||||
content = @Content,
|
||||
display_type = @DisplayType,
|
||||
is_active = @IsActive,
|
||||
starts_at = @StartsAt,
|
||||
ends_at = @EndsAt,
|
||||
sort_order = @SortOrder,
|
||||
updated_at = NOW()
|
||||
WHERE id = @Id",
|
||||
announcement);
|
||||
}
|
||||
|
||||
public async Task DeleteAsync(int id, CancellationToken cancellationToken = default)
|
||||
{
|
||||
using var conn = Conn();
|
||||
await conn.ExecuteAsync("DELETE FROM announcements WHERE id = @Id", new { Id = id });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user