88 lines
2.4 KiB
TypeScript
88 lines
2.4 KiB
TypeScript
import { generateTemplates } from '../../shared/templates'
|
|
import { closeModal, openModal, rerenderModal } from '../components/modal'
|
|
import { apps, setSelectedApp } from '../state'
|
|
import { Button, Form, FormActions, FormError, FormField, FormInput, FormLabel } from '../styles'
|
|
|
|
let newAppError = ''
|
|
let newAppCreating = false
|
|
|
|
async function createNewApp(input: HTMLInputElement) {
|
|
const name = input.value.trim().toLowerCase().replace(/\s+/g, '-')
|
|
|
|
if (!name) {
|
|
newAppError = 'App name is required'
|
|
rerenderModal()
|
|
return
|
|
}
|
|
|
|
if (!/^[a-z][a-z0-9-]*$/.test(name)) {
|
|
newAppError = 'Name must start with a letter and contain only lowercase letters, numbers, and hyphens'
|
|
rerenderModal()
|
|
return
|
|
}
|
|
|
|
if (apps.some(a => a.name === name)) {
|
|
newAppError = 'An app with this name already exists'
|
|
rerenderModal()
|
|
return
|
|
}
|
|
|
|
newAppCreating = true
|
|
newAppError = ''
|
|
rerenderModal()
|
|
|
|
try {
|
|
const templates = generateTemplates(name)
|
|
|
|
for (const [filename, content] of Object.entries(templates)) {
|
|
const res = await fetch(`/api/sync/apps/${name}/files/${filename}`, {
|
|
method: 'PUT',
|
|
body: content,
|
|
})
|
|
if (!res.ok) {
|
|
throw new Error(`Failed to create ${filename}`)
|
|
}
|
|
}
|
|
|
|
// Success - close modal and select the new app
|
|
setSelectedApp(name)
|
|
closeModal()
|
|
} catch (err) {
|
|
newAppError = err instanceof Error ? err.message : 'Failed to create app'
|
|
newAppCreating = false
|
|
rerenderModal()
|
|
}
|
|
}
|
|
|
|
export function openNewAppModal() {
|
|
newAppError = ''
|
|
newAppCreating = false
|
|
|
|
openModal('New App', () => (
|
|
<Form onSubmit={(e: Event) => {
|
|
e.preventDefault()
|
|
const input = (e.target as HTMLFormElement).querySelector('input') as HTMLInputElement
|
|
createNewApp(input)
|
|
}}>
|
|
<FormField>
|
|
<FormLabel for="app-name">App Name</FormLabel>
|
|
<FormInput
|
|
id="app-name"
|
|
type="text"
|
|
placeholder="my-app"
|
|
autofocus
|
|
/>
|
|
{newAppError && <FormError>{newAppError}</FormError>}
|
|
</FormField>
|
|
<FormActions>
|
|
<Button type="button" onClick={closeModal} disabled={newAppCreating}>
|
|
Cancel
|
|
</Button>
|
|
<Button type="submit" variant="primary" disabled={newAppCreating}>
|
|
{newAppCreating ? 'Creating...' : 'Create App'}
|
|
</Button>
|
|
</FormActions>
|
|
</Form>
|
|
))
|
|
}
|