Skip to content
Merged
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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 10 additions & 4 deletions docs/classroom/ui-ux.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,10 @@ Google または Microsoft アカウントでサインインする画面。先
クラス管理のタイトルバー右上(× の左隣)は **アバターメニュー**(メール頭文字 + ▼)に固定。その左に **白一色のベル**(お知らせ)を置く。運営(Admin)からのお知らせが届くと未読数バッジが付く。

- **アバターメニュー**: メール頭文字(`kouji@…`→`K` / `kouji.takao@…`→`KT`)の丸アイコン + ▼。クリックでポップアップ(メール表示 + ログアウト。将来の設定項目もここに集約)。紫背景で視認できる白丸 + 紫文字
- ベルのクリックで一覧パネルを開閉。**開いた時点で全既読**になりバッジが消える(その場では未読ドットで新着を見分けられる)
- パネルは **先頭 5 件**のみ表示。6 件以上あるときは「すべて見る(N件)」で **全件一覧ページ**(`teacher-notifications` フェーズ・**10 件/ページ**)へ遷移
- ベルのクリックで一覧パネルを開閉。**開くだけでは既読にしない**(バッジは残る)。既読はパネルヘッダーの **⋯ メニュー**から明示的に行う
- パネルは **先頭 5 件**のみプレビュー表示。ヘッダーの **⋯ メニュー**に「**すべて既読にする**」「**お知らせを開く**(全件一覧ページ・`teacher-notifications` フェーズ・**10 件/ページ**)」。一覧は件数に関係なく開ける
- お知らせ本文をクリックすると、`link` の種類に応じて該当画面へジャンプ(`kind: 'classroom'` → そのクラスを選択して課題詳細へ / `kind: 'shared-mine'` → みんなの課題の自分の投稿へ)。未知の kind は無視(前方互換)
- **全件一覧ページ**は「**クラス管理 > お知らせ**」パンくず(先頭「クラス管理」でトップ=クラス一覧へ戻れる)+ **左下に「戻る」ボタン**(キャンセルが不適切な画面のポリシー)
- **取得は 1 日 1 回**(コスト削減): その日はじめてクラス管理を開いたときだけ `GET /notifications` を 1 回呼び、localStorage に日付つきでキャッシュ。同じ日の再オープンは API を叩かない(旧 60 秒ポーリングは廃止)。共有 PC 対策として先生メールでキャッシュを識別。取得エラーはクラス管理本体に影響させない(表示しない)。※その日の初回取得後に届いたお知らせは翌日反映(運営連絡は多くて週 1 回程度の前提)
- 送信側は Admin SPA(クラス詳細の「先生へのお知らせ」フォーム → `POST /admin/notifications`)。`docs/admin/README.md` を参照

Expand All @@ -186,12 +187,17 @@ Google または Microsoft アカウントでサインインする画面。先
| ログアウト | `classroom-teacher-logout` | アカウントメニュー内 |
| ベルボタン | `classroom-notifications-button` | クリックでパネル開閉 |
| 未読バッジ | `classroom-notifications-badge` | 未読数(10 以上は「9+」)。未読 0 で非表示 |
| 一覧パネル | `classroom-notifications-panel` | 先頭 5 件 |
| すべて見る | `classroom-notifications-see-all` | 全件一覧ページへ(6 件以上のとき) |
| 一覧パネル | `classroom-notifications-panel` | 先頭 5 件プレビュー |
| ⋯ メニューボタン | `classroom-notifications-menu-button` | パネルヘッダー右の三点 |
| ⋯ メニュー | `classroom-notifications-menu` | — |
| すべて既読にする | `classroom-notifications-mark-all-read` | 全件既読(未読 0 で無効) |
| お知らせを開く | `classroom-notifications-open-all` | 全件一覧ページへ(件数不問) |
| お知らせ 1 件(パネル) | `classroom-notification-item-{notificationId}` | クリックでリンク先へジャンプ + パネルを閉じる |
| 未読ドット | `classroom-notification-unread-dot` | 未読アイテムのみ |
| 空メッセージ | `classroom-notifications-empty` | お知らせ 0 件のとき |
| 全件一覧ページ | `classroom-notifications-page` | `teacher-notifications` フェーズ |
| パンくず先頭 | `classroom-breadcrumb-top` | 「クラス管理」→ トップ(クラス一覧)へ |
| 左下戻る | `classroom-notifications-back` | トップ(クラス一覧)へ戻る |
| ページ内 1 件 | `classroom-notification-page-item-{notificationId}` | クリックでリンク先へジャンプ |
| ページャ | `classroom-notifications-pager` / `-prev` / `-next` | 10 件/ページ |

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -544,8 +544,8 @@
z-index: 1001;
width: 22rem;
max-width: calc(100vw - 2rem);
max-height: 60vh;
overflow-y: auto;
/* プレビューは最大 5 件で高さが有界なのでパネルはスクロールさせない
overflow を付けるとヘッダーの ⋯ ポップアップがクリップされる)。 */
background-color: white;
border: 1px solid #d9d9d9;
border-radius: 0.5rem;
Expand All @@ -555,12 +555,71 @@
}

.notifications-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0.6rem 0.8rem;
font-size: 0.9rem;
font-weight: bold;
border-bottom: 1px solid #e0e0e0;
}

/* ヘッダーの ⋯ メニュー(すべて既読にする / お知らせを開く)。 */
.notifications-menu {
position: relative;
}

.notifications-menu-button {
border: none;
background: none;
color: #888;
font-size: 1.1rem;
line-height: 1;
padding: 0.1rem 0.3rem;
border-radius: 0.3rem;
cursor: pointer;
}

.notifications-menu-button:hover {
background: #f0f0f6;
color: #575e75;
}

.notifications-menu-popup {
position: absolute;
top: 1.8rem;
right: 0;
z-index: 1002;
min-width: 12rem;
background: white;
border: 1px solid #d9d9d9;
border-radius: 0.5rem;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
overflow: hidden;
}

.notifications-menu-item {
display: block;
width: 100%;
padding: 0.6rem 0.9rem;
border: none;
background: none;
text-align: left;
font-size: 0.85rem;
font-weight: normal;
color: #575e75;
cursor: pointer;
}

.notifications-menu-item:hover:not(:disabled) {
background: #f0f6ff;
}

.notifications-menu-item:disabled {
color: #bbb;
cursor: default;
}

.notifications-empty {
padding: 1rem;
font-size: 0.85rem;
Expand Down Expand Up @@ -626,25 +685,7 @@
padding: 1.25rem 2rem 0;
}

/* お知らせパネルの「すべて見る」リンク + 全件一覧ページ + ページネーション。 */
.notifications-see-all {
display: block;
width: 100%;
padding: 0.6rem 0.8rem;
border: none;
border-top: 1px solid #e0e0e0;
background: none;
text-align: center;
font-size: 0.8rem;
font-weight: bold;
color: #4c97ff;
cursor: pointer;
}

.notifications-see-all:hover {
background-color: #f0f6ff;
}

/* お知らせ全件一覧ページ + ページネーション。 */
.notifications-page {
padding: 1.25rem 2rem;
max-width: 48rem;
Expand Down Expand Up @@ -709,6 +750,25 @@
font-variant-numeric: tabular-nums;
}

/* キャンセルが不適切な画面の左下戻るボタン(ポリシー・#1111 レビュー)。 */
.notifications-page-footer {
margin-top: 1.5rem;
}

.notifications-back-button {
border: 1px solid #d0d7e3;
border-radius: 0.4rem;
background: white;
color: #575e75;
padding: 0.4rem 1.1rem;
font-size: 0.9rem;
cursor: pointer;
}

.notifications-back-button:hover {
background: #f0f6ff;
}

.google-courses-view {
padding: 1.25rem 2rem;
max-width: 60rem;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,12 +209,14 @@ const ClassroomTeacherModal = ({ containerProps, onClose }) => {
return (
<div className={styles.mainRelative}>
<div className={styles.detailBreadcrumbs}>
{/* ポリシー: パンくずの先頭「クラス管理」でいつでもトップ
(クラス一覧)へ戻れる(#1111 レビュー)。 */}
<TeacherBreadcrumbs
items={[
{
label: intl.formatMessage(messagesBreadcrumbs.classList),
label: intl.formatMessage(messages.title),
onClick: onShowClassList,
testId: 'classroom-breadcrumb-class-list',
testId: 'classroom-breadcrumb-top',
},
{
label: intl.formatMessage({
Expand All @@ -228,6 +230,7 @@ const ClassroomTeacherModal = ({ containerProps, onClose }) => {
</div>
<TeacherNotificationsList
notifications={notificationsCenter.notifications}
onBack={onShowClassList}
onOpenLink={notificationsCenter.handleOpenLink}
/>
</div>
Expand Down Expand Up @@ -498,6 +501,7 @@ const ClassroomTeacherModal = ({ containerProps, onClose }) => {
isOpen={notificationsCenter.isOpen}
notifications={notificationsCenter.notifications}
unreadCount={notificationsCenter.unreadCount}
onMarkAllRead={notificationsCenter.handleMarkAllRead}
onOpenLink={notificationsCenter.handleOpenLink}
onShowAll={notificationsCenter.handleShowAll}
onToggle={notificationsCenter.handleToggleNotifications}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ NotificationRow.propTypes = {
onOpenLink: PropTypes.func.isRequired,
};

const TeacherNotificationsList = ({ notifications, onOpenLink }) => {
const TeacherNotificationsList = ({ notifications, onBack, onOpenLink }) => {
const [page, setPage] = useState(0);
const totalPages = Math.max(1, Math.ceil(notifications.length / PAGE_SIZE));
const clampedPage = Math.min(page, totalPages - 1);
Expand Down Expand Up @@ -114,12 +114,31 @@ const TeacherNotificationsList = ({ notifications, onOpenLink }) => {
</div>
</React.Fragment>
)}
{/* キャンセルが不適切な画面なので、左下に戻るボタンを置く(ポリシー・
#1111 レビュー)。パンくずの「クラス管理」と同じくトップへ戻る。 */}
{onBack ? (
<div className={styles.notificationsPageFooter}>
<button
className={styles.notificationsBackButton}
data-testid="classroom-notifications-back"
type="button"
onClick={onBack}
>
<FormattedMessage
defaultMessage="Back"
description="Bottom-left back button on the notification list page"
id="gui.classroom.notifications.back"
/>
</button>
</div>
) : null}
</div>
);
};

TeacherNotificationsList.propTypes = {
notifications: PropTypes.arrayOf(PropTypes.object).isRequired,
onBack: PropTypes.func,
onOpenLink: PropTypes.func.isRequired,
};

Expand Down
Loading
Loading