coupon/front/src/stores/wos.store.ts
hyoseung930 14956ac9ec 쿠폰 자동 입력 사이트 작성
## 적용된 변경사항

### 백엔드
- **`wos_coupons` 테이블에 `is_expired` 컬럼 추가** (TypeORM synchronize로 자동 생성)
- **`redeemAll` 로직 개선**:
  - 이미 `성공` / `이미 수령` 로그 있는 쿠폰 → 자동 **스킵** (재지급 안 함)
  - `err_code: 40008` (RECEIVED) → **성공** 처리 (`이미 수령` 메시지)
  - `err_code: 40007` (TIME ERROR) → DB에서 `is_expired = true, is_active = false` 업데이트
- **매일 오전 9시 자동 실행** (`@Cron('0 0 9 * * *')`) - 저장된 모든 유저에게 미수령 쿠폰 자동 지급

### 프론트엔드
- **삭제 버튼 제거**
- 만료된 쿠폰은 **보라색 "만료" 배지** 표시, 토글 버튼 숨김
- 활성 쿠폰 카운트에서 만료 제외
2026-04-16 18:23:16 +09:00

120 lines
2.8 KiB
TypeScript

import { defineStore } from 'pinia';
import axios from 'axios';
interface PlayerInfo {
nickname: string;
avatar_image: string;
stove_lv: number;
}
interface RedeemResult {
name: string;
code: string;
status: 'success' | 'error' | 'pending';
message: string;
}
interface HistoryItem {
id: number;
fid: string;
coupon_code: string;
result_msg: string;
executed_at: string;
}
export interface Coupon {
id: number;
name: string;
code: string;
is_active: boolean;
is_expired: boolean;
created_at: string;
}
export interface SavedUser {
fid: string;
nickname: string;
avatar_url: string;
created_at: string;
}
export const useWosStore = defineStore('wos', {
state: () => ({
fid: '',
player: null as PlayerInfo | null,
results: [] as RedeemResult[],
history: [] as HistoryItem[],
coupons: [] as Coupon[],
savedUsers: [] as SavedUser[],
status: 'idle' as 'idle' | 'loading' | 'success' | 'error',
errorMsg: '',
}),
actions: {
async searchPlayer(fid: string) {
this.status = 'loading';
this.errorMsg = '';
this.player = null;
this.results = [];
try {
const { data } = await axios.post('/api/player', { fid });
this.player = data;
this.fid = fid;
await Promise.all([this.loadHistory(), this.redeemAll()]);
this.status = 'idle';
} catch (err: any) {
this.status = 'error';
this.errorMsg = err.response?.data?.message || '유저를 찾을 수 없습니다.';
}
},
async redeemAll() {
if (!this.fid) return;
try {
const { data } = await axios.post('/api/redeem-all', { fid: this.fid });
this.results = data;
await this.loadHistory();
} catch (err: any) {
this.errorMsg = err.response?.data?.message || '쿠폰 지급 중 오류 발생';
}
},
async loadHistory() {
if (!this.fid) return;
try {
const { data } = await axios.get(`/api/history/${this.fid}`);
this.history = data;
} catch {}
},
async loadSavedUsers() {
try {
const { data } = await axios.get('/api/users');
this.savedUsers = data;
} catch {}
},
async loadCoupons() {
try {
const { data } = await axios.get('/api/coupons');
this.coupons = data;
} catch {}
},
async addCoupon(name: string, code: string) {
await axios.post('/api/coupons', { name, code });
await this.loadCoupons();
},
async toggleCoupon(id: number, is_active: boolean) {
await axios.patch(`/api/coupons/${id}`, { is_active });
await this.loadCoupons();
},
async deleteCoupon(id: number) {
await axios.delete(`/api/coupons/${id}`);
await this.loadCoupons();
},
},
});