---
# System prepended metadata

title: Build out skeleton for AI VO script panel

---

# Build out skeleton for AI VO script panel

Build out the structure and styles for the new automated VO panel without hooking it up to any real data or APIs yet.

- `shared/components/FileBrowserUploadButton.tsx`
    - Make a new, more reusable component for setting up a generic button which opens the computer's file browser for file upload when clicked
    - Props (extends Omit<WaymarkButtonProps, "onClick">):
        - onUploadFiles: (files: File[]) => void
        - acceptedMimeTypes: string[]
            - Passed to the input element to prevent the user from uploading unsupported file types
        - shouldAcceptMultipleFiles?: boolean = false
    - Renders:
        - `<input>` element with type="file"
            - styled with display: none, we'll do all manipulation of the file upload input via a ref
            - multiple = shouldAcceptMultipleFiles
            - accept = acceptedMimeTypes.join(", ")
            - onChange: (event) =>
                - files = Array.from(event.target.files)
                - event.target.value = null
                - if(validateUploadedFiles(files))
                    - onUploadFiles(files)
        - WaymarkButton
            - onClick: () => fileInputRef.current.click()
            - Spread rest of props
- (OPTIONAL BUT NICE TO HAVE) Update `editor/components/EditorFileUploadButton.js` component to use new FileBrowserUploadButton component + convert the file to TS
- `editor/components/panels/AutomatedVoiceOver/`
    - `index.tsx`
        - export default makeEditorControlPanel(VoiceOverUploadPanelHeader, VoiceOverUploadPanelControls);
    - `PanelHeader.tsx`
        - export default AutomatedVoiceOverPanelHeader component
            - Just renders a back button which closes the panel (use targetPanelKey: editorPanelKeys.main to make sure we go all the way back to the main panel)

    - `VOScriptWritingTips.tsx` 
        - `VOScriptWritingTips` component
            - If the user dismisses the tips, we should persist that in localStorage so we don't show it again
            - isOpen state: boolean
                - Lazy initialize to false if `"hasDismissedVOGenerationTips"` key is set in localStorage, otherwise true
            - Wraps contents in `<ToggleCollapseTransition>` component, `isVisible={isOpen}`
                - `<WaymarkButton>` with `<CloseIcon>` in top-right corner
                    - onClick =>
                        - setIsOpen(false)
                        - localStorage.set("hasDismissedVOGenerationTips", "true")`
    - `PanelControls.tsx`
        - export default `AutomatedVoiceOverPanelControls` component
            - `<EditorControlPanelHeading>` w/ the panel's top-level heading + subheading
            - `<EditorControlSectionHeading>`  w/ the "write your script" heading + subheading
            - `<VOScriptWritingTips>`
            - `<form>` element; onSubmit will call the SDK to generate a VO track but we'll leave that stubbed out for now
                - `<SelectInput>`
                - `<WaymarkTextInput>`
                    - `shouldExpandWithDynamicRows`
                    - `minRows={2}`
                    - Styled so that only the top-left and top-right corners are rounded and there's no border-bottom
                - `<div>`
                    - Styled so that it looks like a continuation of the text input; match the background and border colors (except for border-top), make the bottom-left and bottom-right corners rounded
                    - "too short" message + a colored dot are aligned to the right edge of this div (maybe use flex + justify-content: end?)
                        - We can wait to make this message dynamic until we have voice reading speed info available from the SDK
                - `<WaymarkButton>` "Generate AI Voiceover"
                    - `isFormSubmitButton`
            - `<FileBrowserUploadButton>` "Browse for upload"
                - `acceptedMimeTypes`: refer to the `acceptedFileTypes` array passed to the `EditorFileUploadButton` component in `editor/components/panels/VoiceOverUpload/PanelControls.tsx`
        - Register the control panel in `editor/constants/EditorControlPanels.ts`
- `app/state/ducks/offers/selectors.js`
    - Add a new `getBrandingProfileHasAIVoiceOverFeature` selector (reference the `getBrandingProfileHasAudioUpload` selector for an example)
    - We don't know what the field is going to be called yet, let's go with `"has_ai_voiceover"` for now and then we can update it later
    - Comment out the `_.get` and just have this selector return true for testing purposes
- `editor/components/MainControlPanel.tsx`
    - Update `panelButtonConfigs` so that if `getBrandingProfileHasAIVoiceOverFeature` selector is true, make the `panelKey` for the VO button `editorPanelKeys.automatedVoiceOver`, otherwise `editorPanelKeys.voiceOverUpload`