Skip to content

Commit

Permalink
Merge pull request #26 from harley-codes/task/create-posts-page
Browse files Browse the repository at this point in the history
Create Posts Page
  • Loading branch information
harley-codes authored Jun 24, 2024
2 parents f0c2f52 + eeb40e0 commit 5c57e5e
Show file tree
Hide file tree
Showing 20 changed files with 964 additions and 63 deletions.
5 changes: 4 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,16 @@
"editor.tabSize": 2
},
"[typescript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
"editor.defaultFormatter": "vscode.typescript-language-features"
},
"[javascript]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"[typescriptreact]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
},
"[javascriptreact]": {
"editor.defaultFormatter": "dbaeumer.vscode-eslint"
},
"workbench.editor.labelFormat": "short",
}
Binary file modified bun.lockb
Binary file not shown.
32 changes: 32 additions & 0 deletions src/app/dashboard/_actions/postActions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use server'

import { getDatabaseClientAsync } from '@/modules/database/databaseFactory'
import { PostUpdateBlockValues, PostUpdateDetailsValues } from '@/modules/database/requestTypes'
import { PostBlocks, PostDetail } from '@/modules/database/responseTypes'

export async function createPostServerAction(postName: string, projectId: string): Promise<PostDetail>
{
const client = await getDatabaseClientAsync()
const post = await client.createPostAsync(postName, projectId)
return post
}

export async function updatePostServerAction(postId: string, values: PostUpdateDetailsValues): Promise<PostDetail>
{
const client = await getDatabaseClientAsync()
const post = await client.updatePostDetailsAsync(postId, values)
return post
}

export async function updatePostBlocksServerAction(postId: string, values: PostUpdateBlockValues): Promise<PostBlocks>
{
const client = await getDatabaseClientAsync()
const blocks = await client.updatePostBlocksAsync(postId, values)
return blocks
}

export async function deletePostServerAction(postId: string): Promise<void>
{
const client = await getDatabaseClientAsync()
await client.deletePostAsync(postId)
}
4 changes: 2 additions & 2 deletions src/app/dashboard/files/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { NewFileButton } from '@/app/dashboard/files/_components/NewFileButton'
import { getDatabaseClientAsync } from '@/modules/database/databaseFactory'
import { Stack, Typography } from '@mui/material'

const getInitialFilesAsync = async () =>
const getDataAsync = async () =>
{
const client = await getDatabaseClientAsync()
const files = await client.getDataFilesPaginatedAsync(0, Number(process.env.PAGINATION_PAGE_SIZE))
Expand All @@ -12,7 +12,7 @@ const getInitialFilesAsync = async () =>

export default async function FileManagerPage()
{
const files = await getInitialFilesAsync()
const files = await getDataAsync()

return (
<Stack spacing={2}>
Expand Down
11 changes: 11 additions & 0 deletions src/app/dashboard/posts/_components/CreatePostButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'use client'

import { invokeNewPostRequest } from '@/app/dashboard/posts/_components/CreatePostDialog'
import { Button } from '@mui/material'

export function CreatePostButton()
{
return (
<Button onClick={() => invokeNewPostRequest()}>Create Post</Button>
)
}
153 changes: 153 additions & 0 deletions src/app/dashboard/posts/_components/CreatePostDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
'use client'

import { invokeConfirmationModal } from '@/components/ConfirmationModal'
import { invokeMessageAlertModal } from '@/components/MessageAlertModal'
import { createEvent } from '@/modules/custom-events/createEvent'
import { ProjectListDetail } from '@/modules/database/responseTypes'
import { Button, Chip, Dialog, DialogActions, DialogContent, DialogTitle, FormControl, InputLabel, MenuItem, Select, SelectChangeEvent, Stack, TextField, Typography } from '@mui/material'
import { useState } from 'react'

const newPostRequestEvent = createEvent<null>('newPostRequest')

export const invokeNewPostRequest = () => newPostRequestEvent.callEvent(null)

const defaultState = {
display: false,
name: '',
nameInUse: false,
projectId: '',
projectSelected: false,
process: false
}

type Props = {
currentPostNames: string[]
projects: ProjectListDetail[]
onCreatePost: (name: string, projectId: string) => void
}

export function CreatePostDialog(props: Props)
{
const { currentPostNames, projects, onCreatePost } = props

const [state, setState] = useState(defaultState)

newPostRequestEvent.useEvent(() =>
{
setState({ ...defaultState, display: true })
})

function setNameHandler(e: React.ChangeEvent<HTMLInputElement>)
{
setState({
...state,
name: e.currentTarget.value,
nameInUse: currentPostNames.includes(e.currentTarget.value)
})
}

function setProjectHandler(e: SelectChangeEvent<string>)
{
setState({
...state,
projectId: e.target.value,
projectSelected: !!e.target.value
})
}

function cancelHandler()
{
setState({ ...state, display: false, process: false })
}

function createStartHandler()
{
if (state.nameInUse) return

if (!state.name.trim())
{
invokeMessageAlertModal({
title: 'Missing Name',
description: 'You must choose a name first, and cannot by only spaces.',
})
return
}

if (!state.projectSelected)
{
invokeMessageAlertModal({
title: 'Missing Project',
description: 'You must choose a project first.',
})
return
}

invokeConfirmationModal({
description: `Are you sure you want to create a post named "${state.name}"?`,
onConfirmed: (confirmed) =>
{
if (confirmed)
{
setState({ ...state, display: false, process: true })
}
}
})
}

function exitHandler()
{
if (state.process) onCreatePost(state.name, state.projectId)
setState(defaultState)
}

return (
<Dialog
open={state.display}
TransitionProps={{
onExited: exitHandler,
}}
fullWidth maxWidth="xs"
>
<DialogTitle>Create Post</DialogTitle>
<DialogContent>
<TextField
label="Post Name"
margin="normal"
fullWidth
value={state.name}
onChange={setNameHandler}
error={state.nameInUse}
helperText={state.nameInUse ? 'Name already in use' : ' '}
/>
<FormControl fullWidth>
<InputLabel>Assign Project</InputLabel>
<Select
label="Project Status"
value={projects.find(x => x.id === state.projectId)?.id}
onChange={setProjectHandler}
fullWidth
>
{projects.map(({ id, name, active }) => (
<MenuItem key={id} value={id}>
<Stack direction="row" spacing={2} justifyContent="space-between" width="100%">
<Typography variant="inherit">{name}</Typography>
<Chip label="active" size="small" {...(active ? {
color: 'success',
variant: 'outlined'
} : {
color: 'warning',
variant: 'outlined'
})} />
</Stack>
</MenuItem>
))}
</Select>
</FormControl>
</DialogContent>
<DialogActions>
<Button onClick={cancelHandler}>Cancel</Button>
<Button onClick={createStartHandler} disabled={state.nameInUse}>Create</Button>
</DialogActions>
</Dialog>
)
}
Loading

0 comments on commit 5c57e5e

Please sign in to comment.