@aiquants/daily-report 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +150 -0
- package/dist/client.d.mts +449 -0
- package/dist/client.d.ts +449 -0
- package/dist/client.js +7 -0
- package/dist/client.js.map +1 -0
- package/dist/client.mjs +7 -0
- package/dist/client.mjs.map +1 -0
- package/dist/index.d.mts +42 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/dist/logger-D3krZrNK.d.mts +29 -0
- package/dist/logger-D3krZrNK.d.ts +29 -0
- package/dist/server.d.mts +1515 -0
- package/dist/server.d.ts +1515 -0
- package/dist/server.js +10 -0
- package/dist/server.js.map +1 -0
- package/dist/server.mjs +10 -0
- package/dist/server.mjs.map +1 -0
- package/dist/sse-schema-CK7cUnEo.d.ts +1986 -0
- package/dist/sse-schema-yl5AaSsj.d.mts +1986 -0
- package/dist/types-CVhwLhSN.d.mts +76 -0
- package/dist/types-CVhwLhSN.d.ts +76 -0
- package/package.json +108 -0
- package/src/client/components/business-day-thumb-overlay.tsx +19 -0
- package/src/client/components/daily-report-comment-item.tsx +81 -0
- package/src/client/components/daily-report-comment-section.tsx +166 -0
- package/src/client/components/daily-report-detail-list.tsx +676 -0
- package/src/client/components/daily-report-edit-form.tsx +81 -0
- package/src/client/components/daily-report-list.tsx +1024 -0
- package/src/client/components/daily-report-page.tsx +147 -0
- package/src/client/components/daily-report-resolved-content.tsx +139 -0
- package/src/client/components/unread-indicator.tsx +13 -0
- package/src/client/config-context.tsx +129 -0
- package/src/client/contexts/daily-report-action-context.tsx +910 -0
- package/src/client/hooks/use-daily-report-comments.ts +73 -0
- package/src/client/hooks/use-daily-report-sse-connection.ts +86 -0
- package/src/client/hooks/use-daily-report.spec.ts +155 -0
- package/src/client/hooks/use-daily-report.ts +426 -0
- package/src/client/hooks/use-dynamic-viewport-height.ts +127 -0
- package/src/client/route-helpers.ts +76 -0
- package/src/client/ui/button.tsx +42 -0
- package/src/client/ui/cn.ts +14 -0
- package/src/client/ui/input.tsx +21 -0
- package/src/client/ui/label.tsx +16 -0
- package/src/client/ui/switch.tsx +19 -0
- package/src/client/ui/tabs.tsx +40 -0
- package/src/client/ui/textarea.tsx +19 -0
- package/src/client/utils/constants.ts +29 -0
- package/src/client.ts +21 -0
- package/src/index.ts +10 -0
- package/src/server/cache.ts +165 -0
- package/src/server/etag.ts +18 -0
- package/src/server/external-source.ts +60 -0
- package/src/server/handlers.ts +543 -0
- package/src/server/ports.ts +68 -0
- package/src/server/response.ts +37 -0
- package/src/server/schema.ts +266 -0
- package/src/server/service.spec.ts +97 -0
- package/src/server/service.ts +1308 -0
- package/src/server/sse-reader.spec.ts +55 -0
- package/src/server/sse-reader.ts +223 -0
- package/src/server.ts +83 -0
- package/src/shared/business-date.spec.ts +61 -0
- package/src/shared/business-date.ts +84 -0
- package/src/shared/comment-adapter.ts +78 -0
- package/src/shared/logger.ts +47 -0
- package/src/shared/sse-schema.ts +147 -0
- package/src/shared/text-utils.ts +57 -0
- package/src/shared/types.ts +76 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Zod schemas for daily-report SSE messages (client/server shared contract).
|
|
3
|
+
* 日報 SSE メッセージの zod スキーマ (client / server 共有契約)。
|
|
4
|
+
*/
|
|
5
|
+
import { z } from "zod"
|
|
6
|
+
import type { DailyReportCommentItem as DeclaredComment, DailyReportDetail as DeclaredDetail } from "./types"
|
|
7
|
+
|
|
8
|
+
// --- サブスキーマ(types.ts の型と構造的に一致させる) ---
|
|
9
|
+
|
|
10
|
+
export const dailyReportInterviewerSchema = z.object({
|
|
11
|
+
name: z.string(),
|
|
12
|
+
affiliation: z.string().nullable(),
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
export const dailyReportCommentSchema = z.object({
|
|
16
|
+
name: z.string().nullable(),
|
|
17
|
+
text: z.string().nullable(),
|
|
18
|
+
color: z.string().nullable(),
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
export const dailyReportLabelDefSchema = z.object({
|
|
22
|
+
id: z.number(),
|
|
23
|
+
name: z.string(),
|
|
24
|
+
color: z.string().nullable(),
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
export const dailyReportCommentItemSchema = z.object({
|
|
28
|
+
id: z.number(),
|
|
29
|
+
userId: z.string(),
|
|
30
|
+
userName: z.string(),
|
|
31
|
+
content: z.string(),
|
|
32
|
+
createdAt: z.string(),
|
|
33
|
+
isMine: z.boolean(),
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
export const dailyReportDetailSchema = z.object({
|
|
37
|
+
reportHubId: z.number(),
|
|
38
|
+
date: z.string().nullable(),
|
|
39
|
+
createdAt: z.string().nullable(),
|
|
40
|
+
author: z.string(),
|
|
41
|
+
userId: z.string(),
|
|
42
|
+
employeeName: z.string().nullable(),
|
|
43
|
+
updatedBy: z.string().nullable(),
|
|
44
|
+
updatedAt: z.string().nullable(),
|
|
45
|
+
category: z.string().nullable(),
|
|
46
|
+
creationCategory: z.string().nullable(),
|
|
47
|
+
visitTimeFrom: z.string().nullable(),
|
|
48
|
+
visitTimeTo: z.string().nullable(),
|
|
49
|
+
customerName: z.string().nullable(),
|
|
50
|
+
interviewers: z.array(dailyReportInterviewerSchema),
|
|
51
|
+
subject: z.string().nullable(),
|
|
52
|
+
content: z.string().nullable(),
|
|
53
|
+
comments: z.array(dailyReportCommentSchema),
|
|
54
|
+
isRead: z.boolean(),
|
|
55
|
+
isStarred: z.boolean(),
|
|
56
|
+
labels: z.array(dailyReportLabelDefSchema),
|
|
57
|
+
commentItems: z.array(dailyReportCommentItemSchema),
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
// --- SSE メッセージスキーマ(8種) ---
|
|
61
|
+
|
|
62
|
+
export const connectedMessageSchema = z.object({
|
|
63
|
+
type: z.literal("connected"),
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
export const statusUpdateMessageSchema = z.object({
|
|
67
|
+
type: z.literal("status-update"),
|
|
68
|
+
reportHubId: z.number(),
|
|
69
|
+
statusType: z.enum(["star", "read"]),
|
|
70
|
+
value: z.boolean(),
|
|
71
|
+
clientTempId: z.string(),
|
|
72
|
+
// recipientRawUserId はサーバーサイドフィルタリング専用。
|
|
73
|
+
// SSE ルートが raw JSON から取得してフィルタ後に除去する。
|
|
74
|
+
// クライアントには到達しないが、サーバー側の publish で .parse() を通すため定義が必要。
|
|
75
|
+
recipientRawUserId: z.number().optional(),
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
export const commentAddMessageSchema = z.object({
|
|
79
|
+
type: z.literal("comment-add"),
|
|
80
|
+
reportHubId: z.number(),
|
|
81
|
+
comment: dailyReportCommentItemSchema,
|
|
82
|
+
clientTempId: z.string(),
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
export const commentDeleteMessageSchema = z.object({
|
|
86
|
+
type: z.literal("comment-delete"),
|
|
87
|
+
reportHubId: z.number(),
|
|
88
|
+
commentId: z.number(),
|
|
89
|
+
clientTempId: z.string(),
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
export const reportCreateMessageSchema = z.object({
|
|
93
|
+
type: z.literal("report-create"),
|
|
94
|
+
reportHubId: z.number(),
|
|
95
|
+
report: dailyReportDetailSchema,
|
|
96
|
+
clientTempId: z.string(),
|
|
97
|
+
recipientRawUserId: z.number().optional(),
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
export const reportUpdateMessageSchema = z.object({
|
|
101
|
+
type: z.literal("report-update"),
|
|
102
|
+
reportHubId: z.number(),
|
|
103
|
+
report: dailyReportDetailSchema,
|
|
104
|
+
clientTempId: z.string(),
|
|
105
|
+
recipientRawUserId: z.number().optional(),
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
export const reportPublishMessageSchema = z.object({
|
|
109
|
+
type: z.literal("report-publish"),
|
|
110
|
+
reportHubId: z.number(),
|
|
111
|
+
report: dailyReportDetailSchema,
|
|
112
|
+
clientTempId: z.string(),
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
export const reportDeleteMessageSchema = z.object({
|
|
116
|
+
type: z.literal("report-delete"),
|
|
117
|
+
reportHubId: z.number(),
|
|
118
|
+
clientTempId: z.string(),
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
// --- Discriminated Union ---
|
|
122
|
+
|
|
123
|
+
export const dailyReportSseMessageSchema = z.discriminatedUnion("type", [
|
|
124
|
+
connectedMessageSchema,
|
|
125
|
+
statusUpdateMessageSchema,
|
|
126
|
+
commentAddMessageSchema,
|
|
127
|
+
commentDeleteMessageSchema,
|
|
128
|
+
reportCreateMessageSchema,
|
|
129
|
+
reportUpdateMessageSchema,
|
|
130
|
+
reportPublishMessageSchema,
|
|
131
|
+
reportDeleteMessageSchema,
|
|
132
|
+
])
|
|
133
|
+
|
|
134
|
+
// --- 型エクスポート ---
|
|
135
|
+
|
|
136
|
+
export type DailyReportSseMessage = z.infer<typeof dailyReportSseMessageSchema>
|
|
137
|
+
|
|
138
|
+
// --- コンパイル時の型互換チェック ---
|
|
139
|
+
// Zod推論型が既存の型定義に代入可能であることを保証する。
|
|
140
|
+
// ここでエラーが出たらスキーマと types.ts がずれている。
|
|
141
|
+
|
|
142
|
+
type _AssertDetailCompat = z.infer<typeof dailyReportDetailSchema> extends DeclaredDetail ? true : never
|
|
143
|
+
type _AssertCommentCompat = z.infer<typeof dailyReportCommentItemSchema> extends DeclaredComment ? true : never
|
|
144
|
+
const _detailCheck: _AssertDetailCompat = true
|
|
145
|
+
const _commentCheck: _AssertCommentCompat = true
|
|
146
|
+
void _detailCheck
|
|
147
|
+
void _commentCheck
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared text helpers for daily report view components.
|
|
3
|
+
* 日報ビューコンポーネント向けの共通テキストヘルパー。
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Normalizes nullable text by trimming whitespace and applying fallback.
|
|
8
|
+
* null 許容の文字列をトリムしつつフォールバック値を適用する関数。
|
|
9
|
+
*/
|
|
10
|
+
export const fallbackText = (value: string | null | undefined): string => {
|
|
11
|
+
if (!value) {
|
|
12
|
+
return "-"
|
|
13
|
+
}
|
|
14
|
+
const trimmed = value.trim()
|
|
15
|
+
return trimmed === "" ? "-" : trimmed
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Formats a date string to ISO 8601 format (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss).
|
|
20
|
+
* 日付文字列を ISO 8601 形式 (YYYY-MM-DD または YYYY-MM-DDTHH:mm:ss) に整形する関数。
|
|
21
|
+
*/
|
|
22
|
+
export const formatToIsoDate = (value: unknown): string => {
|
|
23
|
+
if (!value) {
|
|
24
|
+
return "-"
|
|
25
|
+
}
|
|
26
|
+
if (typeof value !== "string") {
|
|
27
|
+
// If value is not a string (e.g. Date object), try to convert it to string or handle it
|
|
28
|
+
if (value instanceof Date) {
|
|
29
|
+
return formatToIsoDate(value.toISOString())
|
|
30
|
+
}
|
|
31
|
+
return String(value)
|
|
32
|
+
}
|
|
33
|
+
const trimmed = value.trim()
|
|
34
|
+
if (trimmed === "") {
|
|
35
|
+
return "-"
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const date = new Date(trimmed)
|
|
39
|
+
if (Number.isNaN(date.getTime())) {
|
|
40
|
+
return trimmed
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const year = date.getFullYear()
|
|
44
|
+
const month = String(date.getMonth() + 1).padStart(2, "0")
|
|
45
|
+
const day = String(date.getDate()).padStart(2, "0")
|
|
46
|
+
|
|
47
|
+
const hasTime = trimmed.includes(":") || trimmed.includes("T")
|
|
48
|
+
|
|
49
|
+
if (hasTime) {
|
|
50
|
+
const hours = String(date.getHours()).padStart(2, "0")
|
|
51
|
+
const minutes = String(date.getMinutes()).padStart(2, "0")
|
|
52
|
+
const seconds = String(date.getSeconds()).padStart(2, "0")
|
|
53
|
+
return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}`
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return `${year}-${month}-${day}`
|
|
57
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core data types shared by the daily-report client and server layers.
|
|
3
|
+
* 日報機能の client / server 層で共有するコアデータ型定義。
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/** 日報一覧の 1 アイテム (詳細は遅延読み込み)。 */
|
|
7
|
+
export type DailyReportItem = {
|
|
8
|
+
reportHubId: number
|
|
9
|
+
businessDate: string | null
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** 面談者情報。 */
|
|
13
|
+
export type DailyReportInterviewer = {
|
|
14
|
+
name: string
|
|
15
|
+
affiliation: string | null
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** レガシー形式 (JSON 埋め込み) のコメント。 */
|
|
19
|
+
export type DailyReportComment = {
|
|
20
|
+
name: string | null
|
|
21
|
+
text: string | null
|
|
22
|
+
color: string | null
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/** ラベル定義。 */
|
|
26
|
+
export type DailyReportLabelDef = {
|
|
27
|
+
id: number
|
|
28
|
+
name: string
|
|
29
|
+
color: string | null
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** リレーショナルコメント 1 件。`userId` は難読化済み文字列。 */
|
|
33
|
+
export type DailyReportCommentItem = {
|
|
34
|
+
id: number
|
|
35
|
+
userId: string
|
|
36
|
+
userName: string
|
|
37
|
+
content: string
|
|
38
|
+
createdAt: string
|
|
39
|
+
isMine: boolean
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** 日報詳細 (一覧アイテムの遅延解決結果)。`userId` は難読化済み文字列。 */
|
|
43
|
+
export type DailyReportDetail = {
|
|
44
|
+
reportHubId: number
|
|
45
|
+
date: string | null
|
|
46
|
+
createdAt: string | null
|
|
47
|
+
author: string
|
|
48
|
+
userId: string
|
|
49
|
+
employeeName: string | null
|
|
50
|
+
updatedBy: string | null
|
|
51
|
+
updatedAt: string | null
|
|
52
|
+
category: string | null
|
|
53
|
+
creationCategory: string | null
|
|
54
|
+
visitTimeFrom: string | null
|
|
55
|
+
visitTimeTo: string | null
|
|
56
|
+
customerName: string | null
|
|
57
|
+
interviewers: DailyReportInterviewer[]
|
|
58
|
+
subject: string | null
|
|
59
|
+
content: string | null
|
|
60
|
+
comments: DailyReportComment[]
|
|
61
|
+
isRead: boolean
|
|
62
|
+
isStarred: boolean
|
|
63
|
+
labels: DailyReportLabelDef[]
|
|
64
|
+
commentItems: DailyReportCommentItem[]
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Minimal display-user shape consumed by the client layer.
|
|
69
|
+
* client 層が表示に使う最小ユーザー形状 (Google プロフィール等と構造互換)。
|
|
70
|
+
*/
|
|
71
|
+
export type DailyReportUser = {
|
|
72
|
+
id: string
|
|
73
|
+
displayName?: string
|
|
74
|
+
name?: { familyName?: string; givenName?: string }
|
|
75
|
+
emails?: { value: string }[]
|
|
76
|
+
}
|