mirror of
https://github.com/wasp-lang/wasp.git
synced 2024-11-23 19:29:17 +03:00
Make odoApp in waspc compatible with TypeScript (#960)
This commit is contained in:
parent
b0c20a1f6d
commit
68c7d03814
@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react'
|
||||
import React, { useState, FormEventHandler, ChangeEventHandler } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
import { useQuery } from '@wasp/queries'
|
||||
@ -9,13 +9,27 @@ import updateTaskIsDone from '@wasp/actions/updateTaskIsDone.js'
|
||||
import deleteCompletedTasks from '@wasp/actions/deleteCompletedTasks.js'
|
||||
import toggleAllTasks from '@wasp/actions/toggleAllTasks.js'
|
||||
|
||||
const Todo = (props) => {
|
||||
const { data: tasks, isError, error: tasksError } = useQuery(getTasks)
|
||||
// Copied from Prisma
|
||||
type Task = {
|
||||
id: number
|
||||
description: string
|
||||
isDone: boolean
|
||||
userId: number
|
||||
}
|
||||
|
||||
const isThereAnyTask = () => tasks?.length > 0
|
||||
type GetTasksError = { message: string }
|
||||
|
||||
const TasksError = (props) => {
|
||||
return 'Error during fetching tasks: ' + (tasksError?.message || '')
|
||||
type NonEmptyArray<T> = [T, ...T[]]
|
||||
|
||||
function areThereAnyTasks(tasks: Task[] | undefined): tasks is NonEmptyArray<Task> {
|
||||
return !!(tasks && tasks.length > 0)
|
||||
}
|
||||
|
||||
const Todo = () => {
|
||||
const { data: tasks, isError, error: tasksError } = useQuery<{}, Task[], GetTasksError>(getTasks)
|
||||
|
||||
const TasksError = () => {
|
||||
return <div>{'Error during fetching tasks: ' + (tasksError?.message || '')}</div>
|
||||
}
|
||||
|
||||
return (
|
||||
@ -24,13 +38,13 @@ const Todo = (props) => {
|
||||
<h1>Todos</h1>
|
||||
|
||||
<div className='flex justify-start'>
|
||||
<ToggleAllTasksButton disabled={!isThereAnyTask()} />
|
||||
<ToggleAllTasksButton disabled={!areThereAnyTasks(tasks)} />
|
||||
<NewTaskForm />
|
||||
</div>
|
||||
|
||||
{isError && <TasksError />}
|
||||
|
||||
{isThereAnyTask() && (
|
||||
{areThereAnyTasks(tasks) && (
|
||||
<>
|
||||
<Tasks tasks={tasks} />
|
||||
|
||||
@ -42,9 +56,9 @@ const Todo = (props) => {
|
||||
)
|
||||
}
|
||||
|
||||
const Footer = (props) => {
|
||||
const numCompletedTasks = props.tasks.filter(t => t.isDone).length
|
||||
const numUncompletedTasks = props.tasks.filter(t => !t.isDone).length
|
||||
const Footer = ({ tasks }: { tasks: NonEmptyArray<Task> }) => {
|
||||
const numCompletedTasks = tasks.filter(t => t.isDone).length
|
||||
const numUncompletedTasks = tasks.filter(t => !t.isDone).length
|
||||
|
||||
const handleDeleteCompletedTasks = async () => {
|
||||
try {
|
||||
@ -72,33 +86,35 @@ const Footer = (props) => {
|
||||
)
|
||||
}
|
||||
|
||||
const Tasks = (props) => {
|
||||
const Tasks = ({ tasks }: { tasks: NonEmptyArray<Task> }) => {
|
||||
return (
|
||||
<div>
|
||||
<table className='border-separate border-spacing-2'>
|
||||
<tbody>
|
||||
{props.tasks.map((task, idx) => <Task task={task} key={idx} />)}
|
||||
</tbody>
|
||||
</table>
|
||||
<table className='border-separate border-spacing-2'>
|
||||
<tbody>
|
||||
{tasks.map((task, idx) => <Task task={task} key={idx} />)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const Task = (props) => {
|
||||
const updateTaskIsDoneOptimistically = useAction(updateTaskIsDone, {
|
||||
type UpdateTaskIsDonePayload = Pick<Task, "id" | "isDone">
|
||||
|
||||
const Task = ({ task }: { task: Task }) => {
|
||||
const updateTaskIsDoneOptimistically = useAction<UpdateTaskIsDonePayload, void, Task[]>(updateTaskIsDone, {
|
||||
optimisticUpdates: [{
|
||||
getQuerySpecifier: () => [getTasks],
|
||||
updateQuery: (updatedTask, oldTasks) => {
|
||||
if (oldTasks === undefined) {
|
||||
// cache is empty
|
||||
return [updatedTask];
|
||||
return [{ ...task, ...updatedTask }];
|
||||
} else {
|
||||
return oldTasks.map(task => task.id === updatedTask.id ? { ...task, ...updatedTask } : task)
|
||||
}
|
||||
}
|
||||
}]
|
||||
});
|
||||
const handleTaskIsDoneChange = async (event) => {
|
||||
const handleTaskIsDoneChange: ChangeEventHandler<HTMLInputElement> = async (event) => {
|
||||
const id = parseInt(event.target.id)
|
||||
const isDone = event.target.checked
|
||||
|
||||
@ -114,29 +130,29 @@ const Task = (props) => {
|
||||
<td>
|
||||
<input
|
||||
type='checkbox'
|
||||
id={String(props.task.id)}
|
||||
checked={props.task.isDone}
|
||||
id={String(task.id)}
|
||||
checked={task.isDone}
|
||||
onChange={handleTaskIsDoneChange}
|
||||
color='default'
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<Link to={`/task/${props.task.id}`}> {props.task.description} </Link>
|
||||
<Link to={`/task/${task.id}`}> {task.description} </Link>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
}
|
||||
|
||||
const NewTaskForm = (props) => {
|
||||
const NewTaskForm = () => {
|
||||
const defaultDescription = ''
|
||||
const [description, setDescription] = useState(defaultDescription)
|
||||
|
||||
const createNewTask = async (description) => {
|
||||
const createNewTask = async (description: Task['description']) => {
|
||||
const task = { isDone: false, description }
|
||||
await createTask(task)
|
||||
}
|
||||
|
||||
const handleNewTaskSubmit = async (event) => {
|
||||
const handleNewTaskSubmit: FormEventHandler<HTMLFormElement> = async (event) => {
|
||||
event.preventDefault()
|
||||
try {
|
||||
await createNewTask(description)
|
||||
@ -161,7 +177,7 @@ const NewTaskForm = (props) => {
|
||||
)
|
||||
}
|
||||
|
||||
const ToggleAllTasksButton = (props) => {
|
||||
const ToggleAllTasksButton = ({ disabled }: { disabled: boolean }) => {
|
||||
const handleToggleAllTasks = async () => {
|
||||
try {
|
||||
await toggleAllTasks()
|
||||
@ -173,7 +189,7 @@ const ToggleAllTasksButton = (props) => {
|
||||
return (
|
||||
<button
|
||||
className='btn btn-blue'
|
||||
disabled={props.disabled}
|
||||
disabled={disabled}
|
||||
onClick={handleToggleAllTasks}
|
||||
>
|
||||
✓
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
// The following settings enable IDE support in user-provided source files.
|
||||
// Editing them might break features like import autocompletion and
|
||||
// definition lookup. Don't change them unless you know what you're doing.
|
||||
//
|
||||
// The relative path to the generated web app's root directory. This must be
|
||||
// set to define the "paths" option.
|
||||
"baseUrl": "../../.wasp/out/web-app/",
|
||||
"paths": {
|
||||
// Resolve all "@wasp" imports to the generated source code.
|
||||
"@wasp/*": [
|
||||
"src/*"
|
||||
],
|
||||
// Resolve all non-relative imports to the correct node module. Source:
|
||||
// https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
|
||||
"*": [
|
||||
// Start by looking for the definiton inside the node modules root
|
||||
// directory...
|
||||
"node_modules/*",
|
||||
// ... If that fails, try to find it inside definitely-typed type
|
||||
// definitions.
|
||||
"node_modules/@types/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import React from 'react'
|
||||
|
||||
import logout from '@wasp/auth/logout.js'
|
||||
import Todo from '../Todo.js'
|
||||
import Todo from '../Todo'
|
||||
import '../Main.css'
|
||||
|
||||
const Main = () => {
|
||||
|
60
waspc/examples/todoApp/src/client/react-app-env.d.ts
vendored
Normal file
60
waspc/examples/todoApp/src/client/react-app-env.d.ts
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
declare module '*.avif' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.bmp' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.gif' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.jpg' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.jpeg' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.png' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.webp' {
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.svg' {
|
||||
import * as React from 'react';
|
||||
|
||||
export const ReactComponent: React.FunctionComponent<React.SVGProps<
|
||||
SVGSVGElement
|
||||
> & { title?: string }>;
|
||||
|
||||
const src: string;
|
||||
export default src;
|
||||
}
|
||||
|
||||
declare module '*.module.css' {
|
||||
const classes: { readonly [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
|
||||
declare module '*.module.scss' {
|
||||
const classes: { readonly [key: string]: string };
|
||||
export default classes;
|
||||
}
|
||||
|
||||
declare module '*.module.sass' {
|
||||
const classes: { readonly [key: string]: string };
|
||||
export default classes;
|
||||
}
|
55
waspc/examples/todoApp/src/client/tsconfig.json
Normal file
55
waspc/examples/todoApp/src/client/tsconfig.json
Normal file
@ -0,0 +1,55 @@
|
||||
// =============================== IMPORTANT =================================
|
||||
//
|
||||
// This file is only used for Wasp IDE support. You can change it to configure
|
||||
// your IDE checks, but none of these options will affect the TypeScript
|
||||
// compiler. Proper TS compiler configuration in Wasp is coming soon :)
|
||||
{
|
||||
"compilerOptions": {
|
||||
// JSX support
|
||||
"jsx": "preserve",
|
||||
"strict": true,
|
||||
// Allow default imports.
|
||||
"esModuleInterop": true,
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"allowJs": true,
|
||||
// Wasp needs the following settings enable IDE support in your source
|
||||
// files. Editing them might break features like import autocompletion and
|
||||
// definition lookup. Don't change them unless you know what you're doing.
|
||||
//
|
||||
// The relative path to the generated web app's root directory. This must be
|
||||
// set to define the "paths" option.
|
||||
"baseUrl": "../../.wasp/out/web-app/",
|
||||
"paths": {
|
||||
// Resolve all "@wasp" imports to the generated source code.
|
||||
"@wasp/*": [
|
||||
"src/*"
|
||||
],
|
||||
// Resolve all non-relative imports to the correct node module. Source:
|
||||
// https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
|
||||
"*": [
|
||||
// Start by looking for the definiton inside the node modules root
|
||||
// directory...
|
||||
"node_modules/*",
|
||||
// ... If that fails, try to find it inside definitely-typed type
|
||||
// definitions.
|
||||
"node_modules/@types/*"
|
||||
]
|
||||
},
|
||||
// Correctly resolve types: https://www.typescriptlang.org/tsconfig#typeRoots
|
||||
"typeRoots": [
|
||||
"../../.wasp/out/web-app/node_modules/@types"
|
||||
],
|
||||
// Since this TS config is used only for IDE support and not for
|
||||
// compilation, the following directory doesn't exist. We need to specify
|
||||
// it to prevent this error:
|
||||
// https://stackoverflow.com/questions/42609768/typescript-error-cannot-write-file-because-it-would-overwrite-input-file
|
||||
"outDir": "phantom"
|
||||
},
|
||||
"exclude": [
|
||||
"phantom"
|
||||
],
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
// The following settings enable IDE support in user-provided source files.
|
||||
// Editing them might break features like import autocompletion and
|
||||
// definition lookup. Don't change them unless you know what you're doing.
|
||||
//
|
||||
// The relative path to the generated web app's root directory. This must be
|
||||
// set to define the "paths" option.
|
||||
"baseUrl": "../../.wasp/out/server/",
|
||||
"paths": {
|
||||
// Resolve all "@wasp" imports to the generated source code.
|
||||
"@wasp/*": [
|
||||
"src/*"
|
||||
],
|
||||
// Resolve all non-relative imports to the correct node module. Source:
|
||||
// https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
|
||||
"*": [
|
||||
// Start by looking for the definiton inside the node modules root
|
||||
// directory...
|
||||
"node_modules/*",
|
||||
// ... If that fails, Try to find it inside definitely-typed type
|
||||
// definitions.
|
||||
"node_modules/@types/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
48
waspc/examples/todoApp/src/server/tsconfig.json
Normal file
48
waspc/examples/todoApp/src/server/tsconfig.json
Normal file
@ -0,0 +1,48 @@
|
||||
// =============================== IMPORTANT =================================
|
||||
//
|
||||
// This file is only used for Wasp IDE support. You can change it to configure
|
||||
// your IDE checks, but none of these options will affect the TypeScript
|
||||
// compiler. Proper TS compiler configuration in Wasp is coming soon :)
|
||||
{
|
||||
"compilerOptions": {
|
||||
// Allows default imports.
|
||||
"esModuleInterop": true,
|
||||
"allowJs": true,
|
||||
"strict": true,
|
||||
// Wasp needs the following settings enable IDE support in your source
|
||||
// files. Editing them might break features like import autocompletion and
|
||||
// definition lookup. Don't change them unless you know what you're doing.
|
||||
//
|
||||
// The relative path to the generated web app's root directory. This must be
|
||||
// set to define the "paths" option.
|
||||
"baseUrl": "../../.wasp/out/server/",
|
||||
"paths": {
|
||||
// Resolve all "@wasp" imports to the generated source code.
|
||||
"@wasp/*": [
|
||||
"src/*"
|
||||
],
|
||||
// Resolve all non-relative imports to the correct node module. Source:
|
||||
// https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
|
||||
"*": [
|
||||
// Start by looking for the definiton inside the node modules root
|
||||
// directory...
|
||||
"node_modules/*",
|
||||
// ... If that fails, try to find it inside definitely-typed type
|
||||
// definitions.
|
||||
"node_modules/@types/*"
|
||||
]
|
||||
},
|
||||
// Correctly resolve types: https://www.typescriptlang.org/tsconfig#typeRoots
|
||||
"typeRoots": [
|
||||
"../../.wasp/out/server/node_modules/@types"
|
||||
],
|
||||
// Since this TS config is used only for IDE support and not for
|
||||
// compilation, the following directory doesn't exist. We need to specify
|
||||
// it to prevent this error:
|
||||
// https://stackoverflow.com/questions/42609768/typescript-error-cannot-write-file-because-it-would-overwrite-input-file
|
||||
"outDir": "phantom",
|
||||
},
|
||||
"exclude": [
|
||||
"phantom"
|
||||
],
|
||||
}
|
@ -1,12 +1,15 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
// Enable default imports in TypeScript.
|
||||
"esModuleInterop": true,
|
||||
"allowJs": true,
|
||||
// The following settings enable IDE support in user-provided source files.
|
||||
// Editing them might break features like import autocompletion and
|
||||
// definition lookup. Don't change them unless you know what you're doing.
|
||||
//
|
||||
// The relative path to the generated web app's root directory. This must be
|
||||
// set to define the "paths" option.
|
||||
"baseUrl": "../../.wasp/out/server",
|
||||
"baseUrl": "../../.wasp/out/server/",
|
||||
"paths": {
|
||||
// Resolve all non-relative imports to the correct node module. Source:
|
||||
// https://www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
|
||||
@ -18,6 +21,8 @@
|
||||
// definitions.
|
||||
"node_modules/@types/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
// Correctly resolve types: https://www.typescriptlang.org/tsconfig#typeRoots
|
||||
"typeRoots": ["../../.wasp/out/server/node_modules/@types"]
|
||||
}
|
||||
}
|
@ -29,7 +29,7 @@ app todoApp {
|
||||
setupFn: import setup from "@server/serverSetup.js"
|
||||
},
|
||||
client: {
|
||||
setupFn: import setup from "@client/clientSetup.js"
|
||||
setupFn: import setup from "@client/clientSetup"
|
||||
},
|
||||
db: {
|
||||
system: PostgreSQL
|
||||
|
Loading…
Reference in New Issue
Block a user