PluginProbe
Extendify / 0.11.1
Extendify v0.11.1
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / src / Assist / components / TasksList.js

TasksList.js in Extendify 0.11.1, at src/Assist/components/TasksList.js

127 lines 4.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { ExternalLink, Spinner } from '@wordpress/components'
2 import { __, _n, sprintf } from '@wordpress/i18n'
3 import classNames from 'classnames'
4 import { Checkmark } from '@onboarding/svg'
5 import { useTasks } from '@assist/hooks/useTasks'
6 import {
7 useSelectionStore,
8 useSelectionStoreReady,
9 } from '@assist/state/Selections'
10 import { useTasksStoreReady, useTasksStore } from '@assist/state/Tasks'
11
12 export const TasksList = () => {
13 const { isCompleted } = useTasksStore()
14 const { tasks, loading, error } = useTasks()
15 const readyTasks = useTasksStoreReady()
16 const readyPlugins = useSelectionStoreReady()
17 const pluginBasedGoals = useSelectionStore((state) =>
18 state.plugins?.reduce(
19 (acc, plugin) => [...acc, ...(plugin?.goals ?? [])],
20 [],
21 ),
22 )
23
24 if (loading || !readyTasks || !readyPlugins || error) {
25 return (
26 <div className="my-4 w-full flex items-center max-w-3/4 mx-auto bg-gray-100 p-12">
27 <Spinner />
28 </div>
29 )
30 }
31
32 if (tasks.length === 0) {
33 return (
34 <div className="my-4 max-w-3/4 w-full mx-auto bg-gray-100 p-12">
35 {__('No tasks found...', 'extendify')}
36 </div>
37 )
38 }
39
40 // Filter out tasks that have goal dependencies that don't match the user's goals
41 const tasksFiltered = tasks.filter((task) => {
42 // If no goals, show the task
43 if (!task?.goals?.length) return true
44 // Check if task.goals intersect with pluginBasedGoals
45 return task?.goals?.some((goal) => pluginBasedGoals.includes(goal))
46 })
47 const remainingTasks = tasksFiltered?.reduce(
48 (count, task) => count - Number(isCompleted(task.slug)),
49 tasksFiltered.length,
50 )
51
52 return (
53 <div className="my-4 max-w-3/4 w-full mx-auto bg-gray-100 p-12 pt-10">
54 <div className="mb-6 flex gap-2 items-center justify-center">
55 <h2 className="my-0 text-lg text-center">
56 {__('Get ready to go live', 'extendify')}
57 </h2>
58 {remainingTasks > 0 && (
59 <span
60 title={sprintf(
61 _n(
62 '%s task remaining',
63 '%s tasks remaining',
64 remainingTasks,
65 'extendify',
66 ),
67 remainingTasks,
68 )}
69 className="rounded-full bg-gray-700 text-white text-base px-2 py-0 cursor-default">
70 {remainingTasks}
71 </span>
72 )}
73 </div>
74 <div className="w-full">
75 {tasksFiltered.map((task) => (
76 <TaskCheckBox key={task.slug} task={task} />
77 ))}
78 </div>
79 </div>
80 )
81 }
82
83 const TaskCheckBox = ({ task }) => {
84 const { isCompleted, toggleCompleted } = useTasksStore()
85 return (
86 <div className="p-3 flex border border-solid border-gray-400 bg-white mt-4 relative">
87 <span className="block mt-1 relative">
88 <input
89 id={`task-${task.slug}`}
90 type="checkbox"
91 className={classNames(
92 'hide-checkmark h-6 w-6 rounded-full border-gray-400 outline-none focus:ring-wp ring-partner-primary-bg ring-offset-2 ring-offset-white m-0 focus:outline-none focus:shadow-none',
93 {
94 'bg-partner-primary-bg': isCompleted(task.slug),
95 },
96 )}
97 checked={isCompleted(task.slug)}
98 value={task.slug}
99 name={task.slug}
100 onChange={() => toggleCompleted(task.slug)}
101 />
102 <Checkmark className="text-white fill-current absolute h-6 w-6 block top-0" />
103 </span>
104 <span className="flex flex-col pl-2">
105 <label
106 htmlFor={`task-${task.slug}`}
107 className="text-base font-semibold">
108 <span
109 aria-hidden="true"
110 className="absolute inset-0"></span>
111 {task.title}
112 </label>
113 <span>
114 {task.description}{' '}
115 {task.link && (
116 <ExternalLink
117 className="relative z-10"
118 href={task.link}>
119 {__('Learn more', 'extendify')}
120 </ExternalLink>
121 )}
122 </span>
123 </span>
124 </div>
125 )
126 }
127