はじめに
日報、勤怠、作業ログのような業務アプリでは、前回の入力が未完了のまま次回利用が始まることがあります。
たとえば「出勤は記録したが退勤を押し忘れた」「作業開始は残っているが終了時刻が入っていない」といった状態です。これを専用の一覧画面だけに置いておくと、ユーザーは気づかないまま新しい作業を始めてしまいます。
この記事では、Next.js と Supabase を使う業務アプリで、前回作業日の未完了データを入口画面に出し、記憶が新しいうちに補正してもらうUIパターンを紹介します。
こんな場面で使えます
- 日報や作業ログで、前回分の終了時刻が未入力のまま残る
- 勤怠アプリで、前回作業日の退勤忘れを次回出勤時に直したい
- 在庫確認や点検記録で、前回チェックが途中のまま終わる
- 専用一覧画面へ移動しなくても、直近の未完了だけは自然に気づかせたい
ポイントは「前日」ではなく「直近の作業日」を見ることです。休日や未作業日を挟むアプリでは、単純に昨日を見るだけでは補正対象を見逃します。
解決する問題
未完了データを一覧画面だけに置くと、ユーザーはその画面を開くまで問題に気づけません。
一方で、未完了データをすべて入口画面に出すと、通常操作の邪魔になります。入口画面で扱うのは、直近の作業日に残った1件だけに絞るのが実務では扱いやすいです。
このパターンでは、次の考え方で画面を作ります。
- 直近の作業日を取得する
- 未完了の場合だけ補正カードを表示する
- 補正値を保存するとき、親レコードと明細レコードを同時に整合させる
- 通常の入力導線は邪魔しない
実装例
直近作業日を取得する
まず、今日より前で、作業が開始されている最新の作業日を取得します。
const { data: previousWorkDay } = await supabase
.from("work_days")
.select("*")
.eq("user_id", user.id)
.lt("date", today)
.not("clock_in", "is", null)
.order("date", { ascending: false })
.limit(1)
.maybeSingle()
maybeSingle() を使うと、該当データがない場合もエラー扱いにせず、null として扱えます。初回利用や、過去データがまだないユーザーにも対応しやすくなります。
未完了の場合だけ状態に入れる
取得した直近作業日に退勤時刻がなければ、補正カードの表示対象にします。
if (previousWorkDay && !previousWorkDay.clock_out) {
setPreviousForgotten(previousWorkDay)
} else {
setPreviousForgotten(null)
}
表示条件を状態として分けておくと、JSX側では previousForgotten があるかどうかだけを見ればよくなります。
{previousForgotten && (
<section className="rounded border border-amber-300 bg-amber-50 p-4">
<h2>前回作業日の退勤時刻を確認してください</h2>
<input
type="time"
value={clockOut}
onChange={(event) => setClockOut(event.target.value)}
/>
<button onClick={handleSavePreviousClockOut}>保存する</button>
</section>
)}
補正カードは、メイン画面の上部に置くと気づきやすくなります。ただし、毎回出すのではなく、未完了データがある場合だけ表示します。
保存時に関連データも更新する
作業日テーブルだけを更新すると、明細側の終了時刻や集計値がずれることがあります。最後の作業明細がある場合は、そちらも合わせて更新します。
await supabase
.from("work_days")
.update({
clock_out: `${clockOut}:00`,
status: "finished",
})
.eq("work_day_id", previousWorkDay.work_day_id)
await supabase
.from("work_history")
.update({
ended_at: endedAt,
duration_sec: durationSec,
})
.eq("history_id", lastHistory.history_id)
親レコードと明細レコードの両方を更新することで、画面表示、集計、後続処理が同じ状態を見られます。
UI設計のポイント
このUIは、警告を強く出しすぎるよりも「次の操作へ進む前に、ここだけ確認してください」という見せ方が向いています。
- 通常操作より上に出す
- 入力欄、保存ボタン、参考情報を1つのカードにまとめる
- 補正対象は直近の1件に絞る
- 保存後はカードを消し、通常操作へ戻す
大量の未完了データがある場合は、入口画面で全部処理させるより、専用の一覧画面へ誘導したほうが自然です。
注意点
- 「昨日」固定で判定しない
- 直近以外の未完了データまで入口画面に出しすぎない
- DBカラムを増やす前に、既存テーブルの整合更新で済むか確認する
- 最後の明細が存在しないケースも許容する
- 退勤時刻が出勤時刻より前にならないよう、画面側でも検証する
特に、時刻の逆行チェックは重要です。保存できてしまうと、集計時間がマイナスになったり、グラフ表示が崩れたりします。
らくログタスクでの実績
らくログタスクでは、前回作業日の退勤忘れを次回出勤時に補正できるUIとして実装しました。
ユーザーが新しい作業を始める前に、直近の未完了データだけを画面上部へ出すことで、専用一覧画面へ移動しなくても補正できるようにしています。
関連リンク
まとめ
前回作業日の未完了データは、専用画面に閉じ込めるより、次回利用時の入口画面で自然に気づけるようにすると補正されやすくなります。
Next.js と Supabase では、直近作業日の取得、未完了判定、補正カード表示、関連レコード更新を分けて実装すると、業務アプリでも扱いやすい形にできます。
