> ## Documentation Index
> Fetch the complete documentation index at: https://docs.daytalog.com/llms.txt
> Use this file to discover all available pages before exploring further.

# QC Report

> QC Report with silverstack cue points

<Tabs>
  <Tab title="Preview">
    <Frame className="mt-3">
      <iframe src="https://assets.daytalog.com/example/QCReport.pdf" width="100%" height="842" min-height="100vh" />
    </Frame>
  </Tab>

  <Tab title="Code">
    ```Typescript theme={null}
    import React from 'react';
    import { Page, Text, View, Document, StyleSheet } from '@react-pdf/renderer';
    import { useDaytalog } from 'daytalog';


    /** --- Layout constants  --- */
    const COL_WIDTHS = {
    clip: 60,
    scene: 40,
    shot: 30,
    take: 60,
    qc: 325,
    };
    const QC_WIDTHS = {
    tc: 100,
    category: 60,
    desc: 165,
    };

    const styles = StyleSheet.create({
    page: { fontFamily: 'Helvetica', padding: 40, fontSize: 12 },

    /* ===== Header ===== */
    headerWrap: {
        marginBottom: 14,
    },
    topRow: {
        flexDirection: 'row',
        alignItems: 'flex-end',
        justifyContent: 'space-between',
    },
    titleBlock: { flexGrow: 1, flexShrink: 1, flexBasis: 0, paddingRight: 12 },
    projectName: {
        fontSize: 10,
        letterSpacing: 0.3,
        color: '#666',
        textTransform: 'uppercase',
        marginBottom: 2,
    },
    title: {
        fontSize: 22,
        fontWeight: 'bold',
        lineHeight: 1.1,
    },
    metaBlock: {
        alignItems: 'flex-end',
        minWidth: 180,
    },
    metaLine: {
        fontSize: 9,
        color: '#333',
    },
    divider: {
        marginTop: 10,
        borderBottomWidth: 1,
        borderBottomColor: '#ddd',
    },
    pageNumber: { fontSize: 7, position: 'absolute', top: 20, right: 20, color: '#666' },

    /* ===== Table ===== */
    table: { display: 'table', width: '100%', marginTop: 12 },
    row: { flexDirection: 'row' },
    zebra: { backgroundColor: '#f8f8f8' },

    // Main header (clean)
    headerCellBox: {
        padding: 6,
        borderBottomWidth: 0.8,
        borderBottomColor: '#bbb',
    },
    headerTitle: {
        fontSize: 7,
        fontWeight: 'bold',
        textTransform: 'uppercase',
        letterSpacing: 0.3,
    },

    // QC subheaders INSIDE the QC header cell
    subHeaderRow: {
        flexDirection: 'row',
        paddingTop: 4,
        marginTop: 2,
        borderTopWidth: 0.4,
        borderTopColor: '#ddd',
    },
    subHeaderText: {
        fontSize: 6,
        fontWeight: 'bold',
        color: '#555',
        textTransform: 'uppercase',
    },

    // Body cells
    cellView: { borderBottomWidth: 0.2, borderBottomColor: '#ddd', padding: 0 },
    cellText: { padding: 6, fontSize: 7, color: '#333' },

    // QC rows
    subTable: { display: 'table', width: '100%' },
    subRow: { flexDirection: 'row' },
    subCell: {
        padding: 4,
        fontSize: 7,
        color: '#333',
        borderBottomWidth: 0.2,
        borderBottomColor: '#eee',
    },
    });

    const QCSubTable: React.FC<{ items?: QC[]; fps?: number }> = ({ items = [], fps = 25 }) => {
    if (!items.length) return <Text style={styles.cellText}>—</Text>;
    return (
        <View style={styles.subTable}>
        {items.map((qc, i) => (
            <View key={i} style={styles.subRow} wrap={false}>
            <Text style={[styles.subCell, { width: QC_WIDTHS.tc }]} wrap={false}>
                {formatTimecodeRange(qc.tc, qc.duration, fps)}
            </Text>
            <Text style={[styles.subCell, { width: QC_WIDTHS.category }]} wrap={false}>
                {qc.category || '—'}
            </Text>
            <Text style={[styles.subCell, { width: QC_WIDTHS.desc }]}>{qc.desc || '—'}</Text>
            </View>
        ))}
        </View>
    );
    };

    const QCReport: React.FC = () => {
    const { log, projectName } = useDaytalog();

    const rows = (log?.clips ?? []).map((clip) => ({
        clip: (clip.clip || '').slice(0, 10),
        scene: clip.scene,
        shot: clip.shot,
        take: clip.take,
        qc: { qc: clip.qc ?? [], fps: clip.fps },
    }));

    // Fallback-safe helpers
    const dayLabel = ((): string => {
        try {
        return String(log?.day?.() ?? '—');
        } catch {
        return '—';
        }
    })();
    const dateLabel = ((): string => {
        try {
        return String(log?.date?.('yyyy-mm-dd') ?? log?.date?.('mmddyy') ?? '—');
        } catch {
        return '—';
        }
    })();

    return (
        <Document>
        <Page size='A4' style={styles.page}>
            <Text
            style={styles.pageNumber}
            render={({ pageNumber, totalPages }) =>
                totalPages > 1 ? `Page ${pageNumber} / ${totalPages}` : ''
            }
            fixed
            />

            {/* ===== Header ===== */}
            <View style={styles.headerWrap}>
            <View style={styles.topRow}>
                <View style={styles.titleBlock}>
                <Text style={styles.projectName} wrap={false}>
                    {projectName || 'Untitled Project'}
                </Text>
                <Text style={styles.title} wrap={false}>
                    QC Report
                </Text>
                </View>

                <View style={styles.metaBlock}>
                <Text style={styles.metaLine} wrap={false}>
                    Day: {dayLabel}
                </Text>
                <Text style={styles.metaLine} wrap={false}>
                    Shooting Date: {dateLabel}
                </Text>
                </View>
            </View>
            <View style={styles.divider} />
            </View>

            {/* ===== Table ===== */}
            <View style={styles.table}>
            {/* Header Row */}
            <View style={styles.row} fixed>
                <View style={[styles.headerCellBox, { width: COL_WIDTHS.clip }]}>
                <Text style={styles.headerTitle} wrap={false}>
                    Clip
                </Text>
                </View>
                <View style={[styles.headerCellBox, { width: COL_WIDTHS.scene }]}>
                <Text style={styles.headerTitle} wrap={false}>
                    Scene
                </Text>
                </View>
                <View style={[styles.headerCellBox, { width: COL_WIDTHS.shot }]}>
                <Text style={styles.headerTitle} wrap={false}>
                    Shot
                </Text>
                </View>
                <View style={[styles.headerCellBox, { width: COL_WIDTHS.take }]}>
                <Text style={styles.headerTitle} wrap={false}>
                    Take
                </Text>
                </View>

                {/* QC header with inline subheaders */}
                <View style={[styles.headerCellBox, { width: COL_WIDTHS.qc }]}>
                <Text style={styles.headerTitle} wrap={false}>
                    QC Notes
                </Text>
                <View style={styles.subHeaderRow} wrap={false}>
                    <Text style={[styles.subHeaderText, { width: QC_WIDTHS.tc }]} wrap={false}>
                    Timecode
                    </Text>
                    <Text style={[styles.subHeaderText, { width: QC_WIDTHS.category }]} wrap={false}>
                    Category
                    </Text>
                    <Text style={[styles.subHeaderText, { width: QC_WIDTHS.desc }]} wrap={false}>
                    Description
                    </Text>
                </View>
                </View>
            </View>

            {/* Body */}
            {rows.map((row, rowIndex) => (
                <View
                key={rowIndex}
                style={[styles.row, rowIndex % 2 === 1 ? styles.zebra : {}]}
                wrap={false}
                >
                <View style={[styles.cellView, { width: COL_WIDTHS.clip }]}>
                    <Text style={styles.cellText} wrap={false}>
                    {row.clip ?? '—'}
                    </Text>
                </View>
                <View style={[styles.cellView, { width: COL_WIDTHS.scene }]}>
                    <Text style={styles.cellText} wrap={false}>
                    {row.scene ?? '—'}
                    </Text>
                </View>
                <View style={[styles.cellView, { width: COL_WIDTHS.shot }]}>
                    <Text style={styles.cellText} wrap={false}>
                    {row.shot ?? '—'}
                    </Text>
                </View>
                <View style={[styles.cellView, { width: COL_WIDTHS.take }]}>
                    <Text style={styles.cellText} wrap={false}>
                    {row.take ?? '—'}
                    </Text>
                </View>
                <View style={[styles.cellView, { width: COL_WIDTHS.qc }]}>
                    <QCSubTable items={row.qc.qc} fps={row.qc.fps} />
                </View>
                </View>
            ))}
            </View>
        </Page>
        </Document>
    );
    };

    /** Utilities */
    function pad(n: number, l = 2) {
    return String(n).padStart(l, '0');
    }

    function parseTcToFrames(tc?: string, fps = 25): number | null {
    if (!tc) return null;
    const m = tc.match(/^(\d{1,2}):(\d{2}):(\d{2})[.:](\d{2})$/);
    if (!m) return null;
    const [, H, M, S, F] = m;
    const h = Number(H),
        mnt = Number(M),
        s = Number(S),
        f = Number(F);
    return (h * 3600 + mnt * 60 + s) * fps + f;
    }

    function parseDurationToFrames(dur?: string, fps = 25): number | null {
    if (!dur) return null;
    if (/^\d+$/.test(dur)) return Number(dur); // raw frames
    const frames = parseTcToFrames(dur, fps); // TC-form duration
    return frames !== null ? frames : null;
    }

    /** "HH:MM:SS.FF - HH:MM:SS.FF" */
    function formatTimecodeRange(start?: string, duration?: string, fps = 25): string {
    const startFrames = parseTcToFrames(start, fps);
    const durFrames = parseDurationToFrames(duration, fps);
    if (startFrames === null || durFrames === null) return start || '—';

    const endFrames = startFrames + durFrames;

    const toTc = (frames: number) => {
        const H = Math.floor(frames / (3600 * fps));
        let r = frames % (3600 * fps);
        const M = Math.floor(r / (60 * fps));
        r %= 60 * fps;
        const S = Math.floor(r / fps);
        const F = r % fps;
        return `${pad(H)}:${pad(M)}:${pad(S)}.${pad(F)}`;
    };

    return `${toTc(startFrames)} - ${toTc(endFrames)}`;
    }

    export default QCReport;

    ```
  </Tab>

  <Tab title="Data (.dayta)">
    ```YAML theme={null}
    day: 1
    date: 2025-08-15
    ocf:
      clips:
        - clip: A001C001
        size: 7572467904
        copies:
            - volume: Raid
            hash: 4607f64fcae33728
            - volume: Master_01
            hash: 4607f64fcae33728
            - volume: Backup_01
            hash: 4607f64fcae33728
        tc_start: 10:13:25:08
        tc_end: 10:14:01:13
        duration: 00:00:36:05
        camera_model: CinemaCamera
        reel: A001
        fps: 25
        sensor_fps: 25
        lens: 40 mm
        shutter: 180
        resolution: 4608x3164
        codec: ProRes 4444
        gamma: LOG-C
        ei: 800
        wb: 5300
        tint: "+0.0"
        lut: commercial.cube
        - clip: A001C002
        size: 8642912484
        copies:
            - volume: Raid
            hash: b90261cadf8aab43
            - volume: Master_01
            hash: b90261cadf8aab43
            - volume: Backup_01
            hash: b90261cadf8aab43
        tc_start: 10:15:18:07
        tc_end: 10:15:59:04
        duration: 00:00:40:22
        camera_model: CinemaCamera
        reel: A001
        fps: 25
        sensor_fps: 25
        lens: 40 mm
        shutter: 180
        resolution: 4608x3164
        codec: ProRes 4444
        gamma: LOG-C
        ei: 800
        wb: 5300
        tint: "+0.0"
        lut: commercial.cube
        - clip: A001C003
        size: 13965590828
        copies:
            - volume: Raid
            hash: d21f12407d0ca819
            - volume: Master_01
            hash: d21f12407d0ca819
            - volume: Backup_01
            hash: d21f12407d0ca819
        tc_start: 10:16:28:14
        tc_end: 10:17:35:14
        duration: 00:01:07:00
        camera_model: CinemaCamera
        reel: A001
        fps: 25
        sensor_fps: 25
        lens: 40 mm
        shutter: 180
        resolution: 4608x3164
        codec: ProRes 4444
        gamma: LOG-C
        ei: 800
        wb: 5300
        tint: "+0.0"
        lut: commercial.cube
        - clip: A001C004
        size: 5912345678
        copies:
            - volume: Raid
            hash: a1b2c3d4e5f60718
            - volume: Master_01
            hash: a1b2c3d4e5f60718
            - volume: Backup_01
            hash: a1b2c3d4e5f60718
        tc_start: 10:18:02:02
        tc_end: 10:18:30:20
        duration: 00:00:28:18
        camera_model: CinemaCamera
        reel: A001
        fps: 25
        sensor_fps: 25
        lens: 40 mm
        shutter: 180
        resolution: 4608x3164
        codec: ProRes 4444
        gamma: LOG-C
        ei: 800
        wb: 5300
        tint: "+0.0"
        lut: commercial.cube
        - clip: A001C005
        size: 4023456789
        copies:
            - volume: Raid
            hash: 9f8e7d6c5b4a3210
            - volume: Master_01
            hash: 9f8e7d6c5b4a3210
            - volume: Backup_01
            hash: 9f8e7d6c5b4a3210
        tc_start: 10:18:45:00
        tc_end: 10:19:03:10
        duration: 00:00:18:10
        camera_model: CinemaCamera
        reel: A001
        fps: 25
        sensor_fps: 25
        lens: 40 mm
        shutter: 180
        resolution: 4608x3164
        codec: ProRes 4444
        gamma: LOG-C
        ei: 800
        wb: 5300
        tint: "+0.0"
        lut: commercial.cube
        - clip: A001C006
        size: 15234567890
        copies:
            - volume: Raid
            hash: 1234abcd5678ef90
            - volume: Master_01
            hash: 1234abcd5678ef90
            - volume: Backup_01
            hash: 1234abcd5678ef90
        tc_start: 10:19:10:12
        tc_end: 10:20:23:00
        duration: 00:01:12:13
        camera_model: CinemaCamera
        reel: A001
        fps: 25
        sensor_fps: 25
        lens: 40 mm
        shutter: 180
        resolution: 4608x3164
        codec: ProRes 4444
        gamma: LOG-C
        ei: 800
        wb: 5300
        tint: "+0.0"
        lut: commercial.cube
        - clip: A001C007
        size: 5123456780
        copies:
            - volume: Raid
            hash: fedcba9876543210
            - volume: Master_01
            hash: fedcba9876543210
            - volume: Backup_01
            hash: fedcba9876543210
        tc_start: 10:21:05:00
        tc_end: 10:21:27:05
        duration: 00:00:22:05
        camera_model: CinemaCamera
        reel: A001
        fps: 25
        sensor_fps: 25
        lens: 40 mm
        shutter: 180
        resolution: 4608x3164
        codec: ProRes 4444
        gamma: LOG-C
        ei: 800
        wb: 5300
        tint: "+0.0"
        lut: commercial.cube
        - clip: A001C008
        size: 9434567890
        copies:
            - volume: Raid
            hash: 0a1b2c3d4e5f6789
            - volume: Master_01
            hash: 0a1b2c3d4e5f6789
            - volume: Backup_01
            hash: 0a1b2c3d4e5f6789
        tc_start: 10:21:40:03
        tc_end: 10:22:21:20
        duration: 00:00:41:17
        camera_model: CinemaCamera
        reel: A001
        fps: 25
        sensor_fps: 25
        lens: 40 mm
        shutter: 180
        resolution: 4608x3164
        codec: ProRes 4444
        gamma: LOG-C
        ei: 800
        wb: 5300
        tint: "+0.0"
        lut: commercial.cube
        - clip: A001C009
        size: 7345678901
        copies:
            - volume: Raid
            hash: baddc0ffee12beef
            - volume: Master_01
            hash: baddc0ffee12beef
            - volume: Backup_01
            hash: baddc0ffee12beef
        tc_start: 10:22:35:22
        tc_end: 10:23:11:00
        duration: 00:00:35:03
        camera_model: CinemaCamera
        reel: A001
        fps: 25
        sensor_fps: 25
        lens: 40 mm
        shutter: 180
        resolution: 4608x3164
        codec: ProRes 4444
        gamma: LOG-C
        ei: 800
        wb: 5300
        tint: "+0.0"
        lut: commercial.cube
        - clip: A001C010
        size: 16723456789
        copies:
            - volume: Raid
            hash: cafe0badf00d1234
            - volume: Master_01
            hash: cafe0badf00d1234
            - volume: Backup_01
            hash: cafe0badf00d1234
        tc_start: 10:23:30:00
        tc_end: 10:24:45:12
        duration: 00:01:15:12
        camera_model: CinemaCamera
        reel: A001
        fps: 25
        sensor_fps: 25
        lens: 40 mm
        shutter: 180
        resolution: 4608x3164
        codec: ProRes 4444
        gamma: LOG-C
        ei: 800
        wb: 5300
        tint: "+0.0"
        lut: commercial.cube
        - clip: A001C011
        size: 4987654321
        copies:
            - volume: Raid
            hash: deadbeefc001d00d
            - volume: Master_01
            hash: deadbeefc001d00d
            - volume: Backup_01
            hash: deadbeefc001d00d
        tc_start: 10:25:10:10
        tc_end: 10:25:38:05
        duration: 00:00:27:20
        camera_model: CinemaCamera
        reel: A001
        fps: 25
        sensor_fps: 25
        lens: 40 mm
        shutter: 180
        resolution: 4608x3164
        codec: ProRes 4444
        gamma: LOG-C
        ei: 800
        wb: 5300
        tint: "+0.0"
        lut: commercial.cube
        - clip: A001C012
        size: 10987654321
        copies:
            - volume: Raid
            hash: 0ff1ce0f00dbabe1
            - volume: Master_01
            hash: 0ff1ce0f00dbabe1
            - volume: Backup_01
            hash: 0ff1ce0f00dbabe1
        tc_start: 10:26:05:00
        tc_end: 10:26:59:10
        duration: 00:00:54:10
        camera_model: CinemaCamera
        reel: A001
        fps: 25
        sensor_fps: 25
        lens: 40 mm
        shutter: 180
        resolution: 4608x3164
        codec: ProRes 4444
        gamma: LOG-C
        ei: 800
        wb: 5300
        tint: "+0.0"
        lut: commercial.cube
    custom:
    - schema: Silverstack
        clips:
        - clip: A001C001
            scene: "205"
            shot: "55"
            take: "1"
            qc:
            - tc: 09:21:02.02
                category: Content
                duration: "16"
                desc: Crew in frame
        - clip: A001C002
            scene: "205"
            shot: "55"
            take: "2"
            qc:
            - tc: 09:26:05.09
                category: Sharpness
                duration: "12"
                desc: Not in focus
        - clip: A001C003
            scene: "205"
            shot: "55"
            take: "3"
            qc:
            - tc: 09:56:18.07
                category: Sharpness
                duration: "37"
                desc: Not in focus
        - clip: A001C004
            scene: "205"
            shot: "55"
            take: "4"
        - clip: A001C005
            scene: "205"
            shot: "55"
            take: "5"
        - clip: A001C006
            scene: "205"
            shot: "55"
            take: "6"
            qc:
            - tc: 10:02:18.07
                category: Sharpness
                duration: "30"
                desc: Not in focus
            - tc: 10:03:20.07
                category: Sharpness
                duration: "37"
                desc: Focus 1 m behind actor during dolly move.
        - clip: A001C007
            scene: "205"
            shot: "55"
            take: "7"
        - clip: A001C008
            scene: "205"
            shot: "55"
            take: "8"
        - clip: A001C009
            scene: "205"
            shot: "55"
            take: "9"
        - clip: A001C010
            scene: "205"
            shot: "56"
            take: "1"
        - clip: A001C011
            scene: "205"
            shot: "56"
            take: "2"
        - clip: A001C012
            scene: "205"
            shot: "56"
            take: "3"
    version: 1
    ```
  </Tab>

  <Tab title="Project Settings (config.yaml)">
    ```YAML theme={null}
    project_name: Demo
    custom_schemas:
    - id: Silverstack
        order: 1
        active: true
        sync: clip
        csv_import: true
        clip_fields:
        - type: clip
          column: Name
        - type: text
          key_name: scene
          column: Scene
        - type: text
          key_name: shot
          column: Shot
        - type: text
          key_name: take
          column: Take
        - type: kv_map_list
          key_name: qc
          column: Cue Points
          subfields:
          - key_name: tc
          - key_name: category
          - key_name: duration
          - key_name: desc
          primary_delimiter: ;
          secondary_delimiter: "|"
    version: 1
    ```
  </Tab>
</Tabs>
