Skip to content

Commit ffd4bd1

Browse files
martinovicdevvincanger
authored andcommitted
new icons, demo app improvement (wasp-lang#14)
* new icons, demo app improvement * added prettier
1 parent d6f89ad commit ffd4bd1

File tree

3 files changed

+130
-48
lines changed

3 files changed

+130
-48
lines changed

app/.prettierrc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"trailingComma": "es5",
3+
"semi": true,
4+
"singleQuote": true,
5+
"endOfLine": "lf",
6+
"tabWidth": 2,
7+
"jsxSingleQuote": true
8+
}

app/main.wasp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ app SaaSTemplate {
8383
("@faker-js/faker", "8.3.1"),
8484
("@google-analytics/data", "4.1.0"),
8585
("openai", "^4.24.1"),
86+
("lucide-react", "0.306.0"),
87+
("prettier", "3.1.1"),
88+
("prettier-plugin-tailwindcss", "0.5.11")
8689
],
8790
}
8891

app/src/client/app/DemoAppPage.tsx

Lines changed: 119 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { useQuery } from '@wasp/queries';
77
import getAllTasksByUser from '@wasp/queries/getAllTasksByUser';
88
import { Task } from '@wasp/entities';
99
import { CgSpinner } from 'react-icons/cg';
10+
import { XSquare } from 'lucide-react';
1011

1112
export default function DemoAppPage() {
1213
return (
@@ -35,12 +36,20 @@ export default function DemoAppPage() {
3536
type TodoProps = Pick<Task, 'id' | 'isDone' | 'description' | 'time'>;
3637

3738
function Todo({ id, isDone, description, time }: TodoProps) {
38-
const handleCheckboxChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
39-
await updateTask({ id, isDone: e.currentTarget.checked });
39+
const handleCheckboxChange = async (
40+
e: React.ChangeEvent<HTMLInputElement>
41+
) => {
42+
await updateTask({
43+
id,
44+
isDone: e.currentTarget.checked,
45+
});
4046
};
4147

4248
const handleTimeChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
43-
await updateTask({ id, time: e.currentTarget.value });
49+
await updateTask({
50+
id,
51+
time: e.currentTarget.value,
52+
});
4453
};
4554

4655
const handleDeleteClick = async () => {
@@ -53,43 +62,60 @@ function Todo({ id, isDone, description, time }: TodoProps) {
5362
<div className='flex items-center gap-3'>
5463
<input
5564
type='checkbox'
56-
className='ml-1 form-checkbox bg-purple-500 checked:bg-purple-300 rounded border-purple-600 duration-200 ease-in-out hover:bg-purple-600 hover:checked:bg-purple-600 focus:ring focus:ring-purple-300 focus:checked:bg-purple-400 focus:ring-opacity-50'
65+
className='ml-1 form-checkbox bg-purple-300 checked:bg-purple-300 rounded border-purple-400 duration-200 ease-in-out hover:bg-purple-400 hover:checked:bg-purple-600 focus:ring focus:ring-purple-300 focus:checked:bg-purple-400 focus:ring-opacity-50 text-black'
5766
checked={isDone}
5867
onChange={handleCheckboxChange}
5968
/>
60-
<span className={`text-slate-600 ${isDone ? 'line-through text-slate-500' : ''}`}>{description}</span>
69+
<span
70+
className={`text-slate-600 ${
71+
isDone ? 'line-through text-slate-500' : ''
72+
}`}
73+
>
74+
{description}
75+
</span>
6176
</div>
6277
<div className='flex items-center gap-2'>
6378
<input
6479
id='time'
6580
type='number'
6681
min={0.5}
6782
step={0.5}
68-
className={`w-15 h-8 text-center text-slate-600 text-xs rounded border border-gray-200 focus:outline-none focus:border-transparent focus:ring-2 focus:ring-purple-300 focus:ring-opacity-50 ${
83+
className={`w-18 h-8 text-center text-slate-600 text-xs rounded border border-gray-200 focus:outline-none focus:border-transparent focus:ring-2 focus:ring-purple-300 focus:ring-opacity-50 ${
6984
isDone && 'pointer-events-none opacity-50'
7085
}`}
7186
value={time}
7287
onChange={handleTimeChange}
7388
/>
74-
<span className={`italic text-slate-600 text-xs ${isDone ? 'text-slate-500' : ''}`}>hrs</span>
89+
<span
90+
className={`italic text-slate-600 text-xs ${
91+
isDone ? 'text-slate-500' : ''
92+
}`}
93+
>
94+
hrs
95+
</span>
7596
</div>
7697
</div>
7798
<div className='flex items-center justify-end w-15'>
78-
<button className={`p-1 ${!isDone ? 'hidden' : ''}`} onClick={handleDeleteClick}>
79-
99+
<button className='p-1' onClick={handleDeleteClick} title='Remove task'>
100+
<XSquare size='20' className='text-red-600 hover:text-red-700' />
80101
</button>
81102
</div>
82103
</div>
83104
);
84105
}
85106

86-
function NewTaskForm({ handleCreateTask }: { handleCreateTask: typeof createTask }) {
107+
function NewTaskForm({
108+
handleCreateTask,
109+
}: {
110+
handleCreateTask: typeof createTask;
111+
}) {
87112
const [description, setDescription] = useState<string>('');
88113
const [todaysHours, setTodaysHours] = useState<string>('8');
89114
const [response, setResponse] = useState<any>(null);
90115
const [isPlanGenerating, setIsPlanGenerating] = useState<boolean>(false);
91116

92-
const { data: tasks, isLoading: isTasksLoading } = useQuery(getAllTasksByUser);
117+
const { data: tasks, isLoading: isTasksLoading } =
118+
useQuery(getAllTasksByUser);
93119

94120
useEffect(() => {
95121
console.log('response', response);
@@ -107,7 +133,9 @@ function NewTaskForm({ handleCreateTask }: { handleCreateTask: typeof createTask
107133
const handleGeneratePlan = async () => {
108134
try {
109135
setIsPlanGenerating(true);
110-
const response = await generateGptResponse({ hours: todaysHours });
136+
const response = await generateGptResponse({
137+
hours: todaysHours,
138+
});
111139
if (response) {
112140
console.log('response', response);
113141
setResponse(JSON.parse(response));
@@ -130,6 +158,11 @@ function NewTaskForm({ handleCreateTask }: { handleCreateTask: typeof createTask
130158
placeholder='Enter task description'
131159
value={description}
132160
onChange={(e) => setDescription(e.currentTarget.value)}
161+
onKeyDown={(e) => {
162+
if (e.key === 'Enter') {
163+
handleSubmit();
164+
}
165+
}}
133166
/>
134167
<button
135168
type='button'
@@ -146,50 +179,61 @@ function NewTaskForm({ handleCreateTask }: { handleCreateTask: typeof createTask
146179
{tasks!! && tasks.length > 0 ? (
147180
<div className='space-y-4'>
148181
{tasks.map((task: Task) => (
149-
<Todo key={task.id} id={task.id} isDone={task.isDone} description={task.description} time={task.time} />
182+
<Todo
183+
key={task.id}
184+
id={task.id}
185+
isDone={task.isDone}
186+
description={task.description}
187+
time={task.time}
188+
/>
150189
))}
151-
<div className='flex flex-col gap-3'>
152-
<div className='flex items-center justify-between gap-3'>
153-
<label htmlFor='time' className='text-sm text-gray-600 text-nowrap font-semibold'>
154-
How many hours will you work today?
155-
</label>
156-
<input
157-
type='number'
158-
id='time'
159-
step={0.5}
160-
min={1}
161-
max={24}
162-
className='min-w-[7rem] text-gray-800/90 text-center font-medium rounded-md border border-gray-200 bg-yellow-50 hover:bg-yellow-100 shadow-md focus:outline-none focus:border-transparent focus:shadow-none duration-200 ease-in-out hover:shadow-none'
163-
value={todaysHours}
164-
onChange={(e) => setTodaysHours(e.currentTarget.value)}
165-
/>
166-
</div>
167-
</div>
190+
<div className='flex flex-col gap-3'>
191+
<div className='flex items-center justify-between gap-3'>
192+
<label
193+
htmlFor='time'
194+
className='text-sm text-gray-600 dark:text-gray-300 text-nowrap font-semibold'
195+
>
196+
How many hours will you work today?
197+
</label>
198+
<input
199+
type='number'
200+
id='time'
201+
step={0.5}
202+
min={1}
203+
max={24}
204+
className='min-w-[7rem] text-gray-800/90 text-center font-medium rounded-md border border-gray-200 bg-yellow-50 hover:bg-yellow-100 shadow-md focus:outline-none focus:border-transparent focus:shadow-none duration-200 ease-in-out hover:shadow-none'
205+
value={todaysHours}
206+
onChange={(e) => setTodaysHours(e.currentTarget.value)}
207+
/>
208+
</div>
209+
</div>
168210
</div>
169211
) : (
170212
<div className='text-gray-600 text-center'>Add tasks to begin</div>
171213
)}
172214
</div>
173215

174-
175216
<button
176217
type='button'
177-
disabled={ isPlanGenerating || tasks?.length === 0 }
218+
disabled={isPlanGenerating || tasks?.length === 0}
178219
onClick={() => handleGeneratePlan()}
179220
className='flex items-center justify-center min-w-[7rem] font-medium text-gray-800/90 bg-yellow-50 shadow-md ring-1 ring-inset ring-slate-200 py-2 px-4 rounded-md hover:bg-yellow-100 duration-200 ease-in-out focus:outline-none focus:shadow-none hover:shadow-none disabled:opacity-70 disabled:cursor-not-allowed'
180221
>
181-
{isPlanGenerating ?
182-
<>
183-
<CgSpinner className='inline-block mr-2 animate-spin' />
184-
Generating...
185-
</>
186-
:
187-
'Generate Schedule'}
222+
{isPlanGenerating ? (
223+
<>
224+
<CgSpinner className='inline-block mr-2 animate-spin' />
225+
Generating...
226+
</>
227+
) : (
228+
'Generate Schedule'
229+
)}
188230
</button>
189231

190232
{!!response && (
191233
<div className='flex flex-col'>
192-
<h3 className='text-lg font-semibold text-gray-900 dark:text-white'>Today's Schedule</h3>
234+
<h3 className='text-lg font-semibold text-gray-900 dark:text-white'>
235+
Today's Schedule
236+
</h3>
193237

194238
<TaskTable schedule={response.schedule} />
195239
</div>
@@ -210,11 +254,18 @@ function TaskTable({ schedule }: { schedule: any[] }) {
210254
<tr>
211255
<th
212256
className={`flex items-center justify-between gap-5 py-4 px-3 text-slate-800 border rounded-md border-slate-200 ${
213-
task.priority === 'high' ? 'bg-red-50' : task.priority === 'low' ? 'bg-green-50' : 'bg-yellow-50'
257+
task.priority === 'high'
258+
? 'bg-red-50'
259+
: task.priority === 'low'
260+
? 'bg-green-50'
261+
: 'bg-yellow-50'
214262
}`}
215263
>
216264
<span>{task.name}</span>
217-
<span className='opacity-70 text-xs font-medium italic'> {task.priority} priority</span>
265+
<span className='opacity-70 text-xs font-medium italic'>
266+
{' '}
267+
{task.priority} priority
268+
</span>
218269
</th>
219270
</tr>
220271
</thead>
@@ -224,7 +275,10 @@ function TaskTable({ schedule }: { schedule: any[] }) {
224275
<td
225276
className={`flex items-center justify-between py-2 px-3 text-slate-600 border rounded-md border-purple-100 bg-purple-50`}
226277
>
227-
<Subtask description={subtask.description} time={subtask.time} />
278+
<Subtask
279+
description={subtask.description}
280+
time={subtask.time}
281+
/>
228282
</td>
229283
</tr>
230284
))}
@@ -234,7 +288,10 @@ function TaskTable({ schedule }: { schedule: any[] }) {
234288
<td
235289
className={`flex items-center justify-between py-2 px-3 text-slate-600 border rounded-md border-purple-100 bg-purple-50`}
236290
>
237-
<Subtask description={breakItem.description} time={breakItem.time} />
291+
<Subtask
292+
description={breakItem.description}
293+
time={breakItem.time}
294+
/>
238295
</td>
239296
</tr>
240297
))}
@@ -252,8 +309,10 @@ function Subtask({ description, time }: { description: string; time: number }) {
252309
if (time === 0) return 0;
253310
const hours = Math.floor(time);
254311
const minutes = Math.round((time - hours) * 60);
255-
return `${hours > 0 ? hours + 'hr' : ''} ${minutes > 0 ? minutes + 'min' : ''}`;
256-
}
312+
return `${hours > 0 ? hours + 'hr' : ''} ${
313+
minutes > 0 ? minutes + 'min' : ''
314+
}`;
315+
};
257316

258317
const minutes = useMemo(() => convertHrsToMinutes(time), [time]);
259318

@@ -265,8 +324,20 @@ function Subtask({ description, time }: { description: string; time: number }) {
265324
checked={isDone}
266325
onChange={(e) => setIsDone(e.currentTarget.checked)}
267326
/>
268-
<span className={`text-slate-600 ${isDone ? 'line-through text-slate-500 opacity-50' : ''}`}>{description}</span>
269-
<span className={`text-slate-600 ${isDone ? 'line-through text-slate-500 opacity-50' : ''}`}>{minutes}</span>
327+
<span
328+
className={`text-slate-600 ${
329+
isDone ? 'line-through text-slate-500 opacity-50' : ''
330+
}`}
331+
>
332+
{description}
333+
</span>
334+
<span
335+
className={`text-slate-600 ${
336+
isDone ? 'line-through text-slate-500 opacity-50' : ''
337+
}`}
338+
>
339+
{minutes}
340+
</span>
270341
</>
271342
);
272343
}

0 commit comments

Comments
 (0)