302 lines
11 KiB
JavaScript
302 lines
11 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();
|
|
|
|
// 자동 품앗이 체크 및 실행
|
|
this.checkAutoZzim();
|
|
|
|
} catch (error) {
|
|
console.error('[RestModal] 초기화 실패:', error);
|
|
}
|
|
}
|
|
|
|
async checkAutoZzim() {
|
|
if (this.autoZzim) {
|
|
console.log('[RestModal] 휴식 중 자동 품앗이 시작 (Fast Mode: 10ms)');
|
|
// 백그라운드에 메시지 전송 (100ms 딜레이로 고속 실행)
|
|
try {
|
|
chrome.runtime.sendMessage({
|
|
action: 'autoMutualZzim',
|
|
delay: 100
|
|
});
|
|
} catch (e) {
|
|
console.error('[RestModal] 자동 품앗이 요청 실패:', e);
|
|
}
|
|
}
|
|
}
|
|
|
|
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');
|
|
}
|
|
|
|
console.log('[RestModal] 추천활동 API 호출 (background.js 경유)');
|
|
|
|
// background.js를 통해 API 호출
|
|
const response = await chrome.runtime.sendMessage({
|
|
action: 'getRestActivities',
|
|
token: this.config.ACCESS_TOKEN
|
|
});
|
|
|
|
if (!response || !response.success) {
|
|
throw new Error(response?.error || 'API 호출 실패');
|
|
}
|
|
|
|
const events = response.activities;
|
|
|
|
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');
|
|
}
|
|
|
|
console.log('[RestModal] 어록 API 호출 (background.js 경유)');
|
|
|
|
// background.js를 통해 API 호출
|
|
const response = await chrome.runtime.sendMessage({
|
|
action: 'getRandomSaying',
|
|
token: this.config.ACCESS_TOKEN
|
|
});
|
|
|
|
if (!response || !response.success) {
|
|
throw new Error(response?.error || 'API 호출 실패');
|
|
}
|
|
|
|
const sayings = response.sayings;
|
|
|
|
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();
|
|
});
|