304 lines
12 KiB
JavaScript
304 lines
12 KiB
JavaScript
class RestModal {
|
|
constructor() {
|
|
this.restTime = 5; // 기본 5분
|
|
this.currentTime = this.restTime * 60; // 초 단위
|
|
this.timer = null;
|
|
this.config = null;
|
|
this.currentSaying = null;
|
|
this.autoZzim = false;
|
|
|
|
// 기본 추천 활동 목록 (백엔드 연결 실패 시 사용)
|
|
this.defaultActivities = [
|
|
"🚶♀️ 가벼운 산책을 해보세요",
|
|
"💧 물 한 잔을 마시며 수분을 보충하세요",
|
|
"🧘♀️ 심호흡을 하며 명상을 해보세요",
|
|
"🤸♀️ 간단한 스트레칭으로 몸을 풀어보세요",
|
|
"👀 눈 운동을 하며 눈의 피로를 풀어보세요",
|
|
"🚽 화장실을 다녀오세요",
|
|
"🌱 창밖을 보며 자연을 감상해보세요",
|
|
"📱 잠시 휴대폰을 내려놓고 마음을 비워보세요",
|
|
"☕ 따뜻한 차 한 잔을 마셔보세요",
|
|
"🎵 좋아하는 음악을 들으며 휴식하세요",
|
|
"📚 짧은 글이나 명언을 읽어보세요",
|
|
"🤝 동료나 가족과 간단한 대화를 나누세요",
|
|
"🧴 손 마사지나 목 마사지를 해보세요",
|
|
"🏃♀️ 제자리에서 가볍게 몸을 움직여보세요",
|
|
"🍎 건강한 간식을 드세요"
|
|
];
|
|
|
|
this.activities = []; // 백엔드에서 가져온 활동 목록
|
|
}
|
|
|
|
async init() {
|
|
try {
|
|
await this.loadSettings();
|
|
await this.loadConfig();
|
|
this.setupEventListeners();
|
|
await this.loadRestActivities();
|
|
this.showRandomActivity();
|
|
await this.loadRandomSaying();
|
|
this.startTimer();
|
|
} catch (error) {
|
|
console.error('[RestModal] 초기화 실패:', error);
|
|
}
|
|
}
|
|
|
|
async loadSettings() {
|
|
try {
|
|
const result = await chrome.storage.local.get('time_alarm_settings');
|
|
const settings = result.time_alarm_settings || {};
|
|
|
|
this.restTime = settings.restTime || 5;
|
|
this.autoZzim = settings.autoZzim || false;
|
|
this.currentTime = this.restTime * 60;
|
|
|
|
console.log('[RestModal] 설정 로드:', { restTime: this.restTime, autoZzim: this.autoZzim });
|
|
} catch (error) {
|
|
console.error('[RestModal] 설정 로드 실패:', error);
|
|
}
|
|
}
|
|
|
|
async loadConfig() {
|
|
try {
|
|
const result = await chrome.storage.local.get('settings_config');
|
|
this.config = result.settings_config || {};
|
|
console.log('[RestModal] 설정 정보 로드:', this.config);
|
|
} catch (error) {
|
|
console.error('[RestModal] 설정 정보 로드 실패:', error);
|
|
}
|
|
}
|
|
|
|
setupEventListeners() {
|
|
// 닫기 버튼
|
|
document.getElementById('closeBtn').addEventListener('click', () => {
|
|
this.closeModal();
|
|
});
|
|
|
|
// 건너뛰기 버튼
|
|
document.getElementById('skipBtn').addEventListener('click', () => {
|
|
this.closeModal();
|
|
});
|
|
|
|
// ESC 키로 닫기
|
|
document.addEventListener('keydown', (e) => {
|
|
if (e.key === 'Escape') {
|
|
this.closeModal();
|
|
}
|
|
});
|
|
}
|
|
|
|
async loadRestActivities() {
|
|
try {
|
|
if (!this.config.ACCESS_TOKEN) {
|
|
throw new Error('Access token not found');
|
|
}
|
|
|
|
const SUPABASE_URL = this.config.SUPABASE_URL || "http://146.56.101.199:8000";
|
|
const SUPABASE_ANON_KEY = this.config.SUPABASE_ANON_KEY || "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE";
|
|
|
|
// public.events 테이블에서 event_type이 'rest_time'인 데이터 가져오기
|
|
const apiUrl = `${SUPABASE_URL}/rest/v1/events?select=message&event_type=eq.rest_time&order=created_at.desc&limit=50`;
|
|
|
|
console.log('[RestModal] 추천활동 API 호출:', apiUrl);
|
|
|
|
const response = await fetch(apiUrl, {
|
|
method: 'GET',
|
|
headers: {
|
|
'apikey': SUPABASE_ANON_KEY,
|
|
'Authorization': `Bearer ${this.config.ACCESS_TOKEN}`,
|
|
'Content-Type': 'application/json'
|
|
}
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`API 호출 실패: ${response.status}`);
|
|
}
|
|
|
|
const events = await response.json();
|
|
|
|
if (events && events.length > 0) {
|
|
// message 필드에서 JSON 파싱하여 활동 목록 생성
|
|
this.activities = [];
|
|
|
|
events.forEach(event => {
|
|
try {
|
|
// message 필드가 JSON 형식인 경우 파싱
|
|
const messageData = JSON.parse(event.message);
|
|
|
|
// 활동 텍스트 추출 (다양한 형식 지원)
|
|
if (messageData.activity) {
|
|
this.activities.push(messageData.activity);
|
|
} else if (messageData.text) {
|
|
this.activities.push(messageData.text);
|
|
} else if (typeof messageData === 'string') {
|
|
this.activities.push(messageData);
|
|
}
|
|
} catch (parseError) {
|
|
// JSON 파싱 실패 시 문자열 그대로 사용
|
|
if (typeof event.message === 'string' && event.message.trim()) {
|
|
this.activities.push(event.message);
|
|
}
|
|
}
|
|
});
|
|
|
|
console.log('[RestModal] 백엔드에서 추천활동 로드 완료:', this.activities.length + '개');
|
|
} else {
|
|
throw new Error('추천활동 데이터가 없습니다');
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('[RestModal] 추천활동 로드 실패:', error);
|
|
|
|
// 기본 활동 목록 사용
|
|
this.activities = [...this.defaultActivities];
|
|
console.log('[RestModal] 기본 추천활동 사용:', this.activities.length + '개');
|
|
}
|
|
}
|
|
|
|
showRandomActivity() {
|
|
if (this.activities.length === 0) {
|
|
this.activities = [...this.defaultActivities];
|
|
}
|
|
|
|
const randomActivity = this.activities[Math.floor(Math.random() * this.activities.length)];
|
|
document.getElementById('activitySuggestion').innerHTML = randomActivity;
|
|
}
|
|
|
|
async loadRandomSaying() {
|
|
try {
|
|
if (!this.config.ACCESS_TOKEN) {
|
|
throw new Error('Access token not found');
|
|
}
|
|
|
|
const SUPABASE_URL = this.config.SUPABASE_URL || "http://146.56.101.199:8000";
|
|
const SUPABASE_ANON_KEY = this.config.SUPABASE_ANON_KEY || "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE";
|
|
|
|
// 최근 1달 이내의 승인된 어록 가져오기
|
|
const oneMonthAgo = new Date();
|
|
oneMonthAgo.setMonth(oneMonthAgo.getMonth() - 1);
|
|
|
|
const apiUrl = `${SUPABASE_URL}/rest/v1/tanya_sayings?select=*,sayings_cat(saying_cat),sayings_target(target)&created_at=gte.${oneMonthAgo.toISOString()}&admin_approval=eq.true&order=created_at.desc&limit=50`;
|
|
|
|
console.log('[RestModal] 어록 API 호출:', apiUrl);
|
|
|
|
const response = await fetch(apiUrl, {
|
|
method: 'GET',
|
|
headers: {
|
|
'apikey': SUPABASE_ANON_KEY,
|
|
'Authorization': `Bearer ${this.config.ACCESS_TOKEN}`,
|
|
'Content-Type': 'application/json'
|
|
}
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`API 호출 실패: ${response.status}`);
|
|
}
|
|
|
|
const sayings = await response.json();
|
|
|
|
if (sayings && sayings.length > 0) {
|
|
// 랜덤하게 하나 선택
|
|
const randomSaying = sayings[Math.floor(Math.random() * sayings.length)];
|
|
this.currentSaying = randomSaying;
|
|
|
|
// 어록 표시
|
|
const sayingContent = document.getElementById('sayingContent');
|
|
const sayingAuthor = document.getElementById('sayingAuthor');
|
|
|
|
sayingContent.innerHTML = `"${randomSaying.saying}"`;
|
|
|
|
// 카테고리와 대상 정보 표시
|
|
const category = randomSaying.sayings_cat?.saying_cat || '';
|
|
const target = randomSaying.sayings_target?.target || '';
|
|
const dateStr = new Date(randomSaying.created_at).toLocaleDateString('ko-KR');
|
|
|
|
sayingAuthor.innerHTML = `${category} ${target ? `• ${target}` : ''} • ${dateStr}`;
|
|
|
|
console.log('[RestModal] 어록 로드 완료:', randomSaying);
|
|
} else {
|
|
throw new Error('어록이 없습니다');
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error('[RestModal] 어록 로드 실패:', error);
|
|
|
|
// 기본 메시지 표시
|
|
document.getElementById('sayingContent').innerHTML = '"열심히 일한 당신, 잠시 휴식을 취하며 에너지를 충전하세요!"';
|
|
document.getElementById('sayingAuthor').innerHTML = '타냐 • 휴식 메시지';
|
|
}
|
|
}
|
|
|
|
startTimer() {
|
|
this.updateTimerDisplay();
|
|
this.updateProgressBar();
|
|
|
|
this.timer = setInterval(() => {
|
|
this.currentTime--;
|
|
|
|
this.updateTimerDisplay();
|
|
this.updateProgressBar();
|
|
|
|
if (this.currentTime <= 0) {
|
|
this.onTimerComplete();
|
|
}
|
|
}, 1000);
|
|
}
|
|
|
|
updateTimerDisplay() {
|
|
const minutes = Math.floor(this.currentTime / 60);
|
|
const seconds = this.currentTime % 60;
|
|
const display = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
|
|
|
|
document.getElementById('timerDisplay').textContent = display;
|
|
}
|
|
|
|
updateProgressBar() {
|
|
const totalTime = this.restTime * 60;
|
|
const elapsed = totalTime - this.currentTime;
|
|
const percentage = (elapsed / totalTime) * 100;
|
|
|
|
document.getElementById('progressFill').style.width = `${percentage}%`;
|
|
}
|
|
|
|
async onTimerComplete() {
|
|
clearInterval(this.timer);
|
|
|
|
// 완료 메시지 표시
|
|
this.showCompletionMessage();
|
|
|
|
// 3초 후 자동 닫기
|
|
setTimeout(() => {
|
|
this.closeModal();
|
|
}, 3000);
|
|
}
|
|
|
|
showCompletionMessage() {
|
|
const modalContainer = document.querySelector('.modal-container');
|
|
modalContainer.innerHTML = `
|
|
<div class="rest-icon">🚀</div>
|
|
<h1 class="rest-title">휴식 완료!</h1>
|
|
<p class="rest-subtitle">이제 다시 열심히 월매출 1억을 향해 달려가세요!</p>
|
|
<div style="font-size: 1.2rem; color: #667eea; margin-top: 20px;">
|
|
💪 화이팅! 성공은 바로 앞에 있습니다!
|
|
</div>
|
|
<div class="actions" style="margin-top: 30px;">
|
|
<button class="btn btn-primary" onclick="window.close()">확인</button>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
closeModal() {
|
|
if (this.timer) {
|
|
clearInterval(this.timer);
|
|
}
|
|
|
|
// 창 닫기
|
|
window.close();
|
|
}
|
|
}
|
|
|
|
// 페이지 로드 시 휴식 모달 초기화
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
const restModal = new RestModal();
|
|
restModal.init();
|
|
});
|