Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/UseCases/Web/tests/test_habit_task_log_calendar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import pytest
from flask import Flask
from src.routes.web.habit import views_blueprint

@pytest.fixture
def app():
app = Flask(__name__)
app.secret_key = 'test'
app.register_blueprint(views_blueprint)
return app

def test_habit_task_log_calendar_toggle(client, app):
# Simulate login and minimal session
with app.test_client() as client:
with client.session_transaction() as sess:
sess['login_name'] = 'testuser'
sess['login_email'] = 'test@example.com'
sess['user_id'] = 'dummyid'
# Assume a dummy task_id exists, or mock the repository if needed
response = client.get('/habit/dummyid')
html = response.get_data(as_text=True)
assert 'toggle-view-btn' in html
assert 'calendar-view' in html
assert 'カレンダー表示に切替' in html
58 changes: 58 additions & 0 deletions src/templates/pages/habit/detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ <h4>習慣タスク実績</h4>
<a href="{{ url_for('views_blueprint.view_habit_task_list') }}" class="btn btn-outline-secondary btn-sm">一覧へ戻る</a>
</div>
</div>
<div class="row mb-3">
<div class="col">
<button id="toggle-view-btn" class="btn btn-primary btn-sm">カレンダー表示に切替</button>
</div>
</div>
<div id="calendar-view" class="mb-4" style="display:none;"></div>

<div class="row">
<div class="col">
Expand Down Expand Up @@ -45,6 +51,58 @@ <h4>習慣タスク実績</h4>
{% endfor %}
{% if page_contents.data.logs|length == 0 %}
<tr><td colspan="4" class="text-muted">実績はまだありません。</td></tr>
<script>
// Simple calendar rendering (no external library)
function renderCalendar(logs) {
const today = new Date();
const year = today.getFullYear();
const month = today.getMonth();
const firstDay = new Date(year, month, 1);
const lastDay = new Date(year, month + 1, 0);
let html = '<table class="table table-bordered text-center"><thead><tr>';
const weekDays = ['日', '月', '火', '水', '木', '金', '土'];
for (const wd of weekDays) html += `<th>${wd}</th>`;
html += '</tr></thead><tbody><tr>';
for (let i = 0; i < firstDay.getDay(); i++) html += '<td></td>';
const logMap = {};
logs.forEach(log => { logMap[log.scheduled_date] = log; });
for (let d = 1; d <= lastDay.getDate(); d++) {
const dateStr = `${year}-${String(month+1).padStart(2,'0')}-${String(d).padStart(2,'0')}`;
const log = logMap[dateStr];
let cell = d;
if (log) {
if (log.result === 'done') cell = `<span class='text-success fw-bold'>${d}✓</span>`;
else if (log.result === 'not_done') cell = `<span class='text-danger fw-bold'>${d}×</span>`;
else cell = `<span class='text-secondary'>${d}?</span>`;
}
html += `<td>${cell}</td>`;
if ((firstDay.getDay() + d) % 7 === 0) html += '</tr><tr>';
}
for (let i = (firstDay.getDay() + lastDay.getDate()) % 7; i < 7 && i !== 0; i++) html += '<td></td>';
html += '</tr></tbody></table>';
return html;
}

const logs = JSON.parse('{{ page_contents.data.logs|tojson|safe }}');
const calendarView = document.getElementById('calendar-view');
const tableView = document.querySelector('.table-striped').parentElement.parentElement;
const toggleBtn = document.getElementById('toggle-view-btn');
let calendarMode = false;
toggleBtn.addEventListener('click', function() {
calendarMode = !calendarMode;
if (calendarMode) {
calendarView.innerHTML = renderCalendar(logs);
calendarView.style.display = '';
tableView.style.display = 'none';
toggleBtn.textContent = 'リスト表示に切替';
} else {
calendarView.style.display = 'none';
tableView.style.display = '';
toggleBtn.textContent = 'カレンダー表示に切替';
}
});
</script>

{% endif %}
</tbody>
</table>
Expand Down