@canva/cli 1.19.0 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +1 -9
  3. package/cli.js +625 -626
  4. package/package.json +2 -3
  5. package/templates/base/backend/base_backend/create.ts +0 -114
  6. package/templates/base/backend/database/database.ts +0 -42
  7. package/templates/base/backend/routers/auth.ts +0 -288
  8. package/templates/base/declarations/declarations.d.ts +0 -29
  9. package/templates/base/eslint.config.mjs +0 -14
  10. package/templates/base/package.json +0 -91
  11. package/templates/base/scripts/copy_env.ts +0 -13
  12. package/templates/base/scripts/ssl/ssl.ts +0 -131
  13. package/templates/base/scripts/start/app_runner.ts +0 -223
  14. package/templates/base/scripts/start/context.ts +0 -171
  15. package/templates/base/scripts/start/start.ts +0 -46
  16. package/templates/base/scripts/start.tests.ts +0 -61
  17. package/templates/base/styles/components.css +0 -38
  18. package/templates/base/tsconfig.json +0 -56
  19. package/templates/base/webpack.config.ts +0 -247
  20. package/templates/common/.env.template +0 -6
  21. package/templates/common/.gitignore.template +0 -8
  22. package/templates/common/.nvmrc +0 -1
  23. package/templates/common/.prettierrc +0 -21
  24. package/templates/common/LICENSE.md +0 -48
  25. package/templates/common/README.md +0 -179
  26. package/templates/common/jest.config.mjs +0 -35
  27. package/templates/common/jest.setup.ts +0 -35
  28. package/templates/content_publisher/README.md +0 -58
  29. package/templates/content_publisher/canva-app.json +0 -17
  30. package/templates/content_publisher/declarations/declarations.d.ts +0 -29
  31. package/templates/content_publisher/eslint.config.mjs +0 -14
  32. package/templates/content_publisher/package.json +0 -90
  33. package/templates/content_publisher/scripts/copy_env.ts +0 -13
  34. package/templates/content_publisher/scripts/ssl/ssl.ts +0 -131
  35. package/templates/content_publisher/scripts/start/app_runner.ts +0 -223
  36. package/templates/content_publisher/scripts/start/context.ts +0 -171
  37. package/templates/content_publisher/scripts/start/start.ts +0 -46
  38. package/templates/content_publisher/src/index.tsx +0 -4
  39. package/templates/content_publisher/src/intents/content_publisher/index.tsx +0 -107
  40. package/templates/content_publisher/src/intents/content_publisher/post_preview.tsx +0 -240
  41. package/templates/content_publisher/src/intents/content_publisher/preview_ui.tsx +0 -62
  42. package/templates/content_publisher/src/intents/content_publisher/settings_ui.tsx +0 -81
  43. package/templates/content_publisher/src/intents/content_publisher/types.ts +0 -29
  44. package/templates/content_publisher/styles/components.css +0 -38
  45. package/templates/content_publisher/styles/preview_ui.css +0 -49
  46. package/templates/content_publisher/tsconfig.json +0 -56
  47. package/templates/content_publisher/webpack.config.ts +0 -247
  48. package/templates/dam/backend/routers/dam.ts +0 -108
  49. package/templates/dam/backend/server.ts +0 -65
  50. package/templates/dam/canva-app.json +0 -25
  51. package/templates/dam/declarations/declarations.d.ts +0 -29
  52. package/templates/dam/eslint.config.mjs +0 -14
  53. package/templates/dam/package.json +0 -97
  54. package/templates/dam/scripts/copy_env.ts +0 -13
  55. package/templates/dam/scripts/ssl/ssl.ts +0 -131
  56. package/templates/dam/scripts/start/app_runner.ts +0 -223
  57. package/templates/dam/scripts/start/context.ts +0 -171
  58. package/templates/dam/scripts/start/start.ts +0 -46
  59. package/templates/dam/src/index.tsx +0 -4
  60. package/templates/dam/src/intents/design_editor/adapter.ts +0 -44
  61. package/templates/dam/src/intents/design_editor/app.tsx +0 -35
  62. package/templates/dam/src/intents/design_editor/config.ts +0 -220
  63. package/templates/dam/src/intents/design_editor/index.css +0 -3
  64. package/templates/dam/src/intents/design_editor/index.tsx +0 -25
  65. package/templates/dam/tsconfig.json +0 -56
  66. package/templates/dam/utils/backend/base_backend/create.ts +0 -114
  67. package/templates/dam/webpack.config.ts +0 -247
  68. package/templates/data_connector/README.md +0 -84
  69. package/templates/data_connector/canva-app.json +0 -21
  70. package/templates/data_connector/declarations/declarations.d.ts +0 -29
  71. package/templates/data_connector/eslint.config.mjs +0 -14
  72. package/templates/data_connector/package.json +0 -92
  73. package/templates/data_connector/scripts/copy_env.ts +0 -13
  74. package/templates/data_connector/scripts/ssl/ssl.ts +0 -131
  75. package/templates/data_connector/scripts/start/app_runner.ts +0 -223
  76. package/templates/data_connector/scripts/start/context.ts +0 -171
  77. package/templates/data_connector/scripts/start/start.ts +0 -46
  78. package/templates/data_connector/src/api/connect_client.ts +0 -6
  79. package/templates/data_connector/src/api/data_source.ts +0 -97
  80. package/templates/data_connector/src/api/data_sources/designs.tsx +0 -296
  81. package/templates/data_connector/src/api/data_sources/index.ts +0 -4
  82. package/templates/data_connector/src/api/data_sources/templates.tsx +0 -328
  83. package/templates/data_connector/src/api/fetch_data_table.ts +0 -55
  84. package/templates/data_connector/src/api/index.ts +0 -4
  85. package/templates/data_connector/src/api/oauth.ts +0 -8
  86. package/templates/data_connector/src/api/tests/data_source.test.tsx +0 -99
  87. package/templates/data_connector/src/components/app_error.tsx +0 -15
  88. package/templates/data_connector/src/components/footer.tsx +0 -26
  89. package/templates/data_connector/src/components/header.tsx +0 -40
  90. package/templates/data_connector/src/components/index.ts +0 -3
  91. package/templates/data_connector/src/components/inputs/messages.tsx +0 -95
  92. package/templates/data_connector/src/components/inputs/search_filter.tsx +0 -109
  93. package/templates/data_connector/src/components/inputs/select_field.tsx +0 -26
  94. package/templates/data_connector/src/context/app_context.tsx +0 -125
  95. package/templates/data_connector/src/context/index.ts +0 -2
  96. package/templates/data_connector/src/context/use_app_context.ts +0 -17
  97. package/templates/data_connector/src/index.tsx +0 -4
  98. package/templates/data_connector/src/intents/data_connector/app.tsx +0 -20
  99. package/templates/data_connector/src/intents/data_connector/entrypoint.tsx +0 -70
  100. package/templates/data_connector/src/intents/data_connector/home.tsx +0 -21
  101. package/templates/data_connector/src/intents/data_connector/index.tsx +0 -56
  102. package/templates/data_connector/src/pages/data_source_config.tsx +0 -9
  103. package/templates/data_connector/src/pages/error.tsx +0 -37
  104. package/templates/data_connector/src/pages/index.ts +0 -4
  105. package/templates/data_connector/src/pages/login.tsx +0 -145
  106. package/templates/data_connector/src/pages/select_source.tsx +0 -24
  107. package/templates/data_connector/src/routes/index.ts +0 -2
  108. package/templates/data_connector/src/routes/paths.ts +0 -7
  109. package/templates/data_connector/src/routes/protected_route.tsx +0 -26
  110. package/templates/data_connector/src/routes/routes.tsx +0 -42
  111. package/templates/data_connector/src/utils/data_params.ts +0 -17
  112. package/templates/data_connector/src/utils/data_table.ts +0 -116
  113. package/templates/data_connector/src/utils/fetch_result.ts +0 -36
  114. package/templates/data_connector/src/utils/index.ts +0 -2
  115. package/templates/data_connector/src/utils/tests/data_table.test.ts +0 -133
  116. package/templates/data_connector/styles/components.css +0 -38
  117. package/templates/data_connector/tsconfig.json +0 -56
  118. package/templates/data_connector/webpack.config.ts +0 -247
  119. package/templates/gen_ai/README.md +0 -27
  120. package/templates/gen_ai/backend/routers/image.ts +0 -232
  121. package/templates/gen_ai/backend/server.ts +0 -65
  122. package/templates/gen_ai/canva-app.json +0 -25
  123. package/templates/gen_ai/declarations/declarations.d.ts +0 -29
  124. package/templates/gen_ai/eslint.config.mjs +0 -14
  125. package/templates/gen_ai/package.json +0 -101
  126. package/templates/gen_ai/scripts/copy_env.ts +0 -13
  127. package/templates/gen_ai/scripts/ssl/ssl.ts +0 -131
  128. package/templates/gen_ai/scripts/start/app_runner.ts +0 -223
  129. package/templates/gen_ai/scripts/start/context.ts +0 -171
  130. package/templates/gen_ai/scripts/start/start.ts +0 -46
  131. package/templates/gen_ai/src/api/api.ts +0 -194
  132. package/templates/gen_ai/src/api/index.ts +0 -1
  133. package/templates/gen_ai/src/components/app_error.tsx +0 -18
  134. package/templates/gen_ai/src/components/footer.messages.ts +0 -48
  135. package/templates/gen_ai/src/components/footer.tsx +0 -156
  136. package/templates/gen_ai/src/components/image_grid.tsx +0 -103
  137. package/templates/gen_ai/src/components/index.ts +0 -7
  138. package/templates/gen_ai/src/components/loading_results.tsx +0 -169
  139. package/templates/gen_ai/src/components/prompt_input.messages.ts +0 -14
  140. package/templates/gen_ai/src/components/prompt_input.tsx +0 -154
  141. package/templates/gen_ai/src/components/remaining_credits.tsx +0 -84
  142. package/templates/gen_ai/src/components/report_box.tsx +0 -54
  143. package/templates/gen_ai/src/components/tests/remaining_credit.tests.tsx +0 -47
  144. package/templates/gen_ai/src/config.ts +0 -21
  145. package/templates/gen_ai/src/context/app_context.tsx +0 -153
  146. package/templates/gen_ai/src/context/context.messages.ts +0 -30
  147. package/templates/gen_ai/src/context/index.ts +0 -2
  148. package/templates/gen_ai/src/context/use_app_context.ts +0 -17
  149. package/templates/gen_ai/src/index.tsx +0 -4
  150. package/templates/gen_ai/src/intents/design_editor/app.tsx +0 -19
  151. package/templates/gen_ai/src/intents/design_editor/home.tsx +0 -13
  152. package/templates/gen_ai/src/intents/design_editor/index.tsx +0 -17
  153. package/templates/gen_ai/src/pages/error.tsx +0 -41
  154. package/templates/gen_ai/src/pages/generate.tsx +0 -9
  155. package/templates/gen_ai/src/pages/index.ts +0 -3
  156. package/templates/gen_ai/src/pages/results.tsx +0 -31
  157. package/templates/gen_ai/src/routes/index.ts +0 -1
  158. package/templates/gen_ai/src/routes/paths.ts +0 -4
  159. package/templates/gen_ai/src/routes/routes.tsx +0 -24
  160. package/templates/gen_ai/src/utils/index.ts +0 -1
  161. package/templates/gen_ai/src/utils/obscenity_filter.ts +0 -33
  162. package/templates/gen_ai/styles/components.css +0 -38
  163. package/templates/gen_ai/styles/utils.css +0 -3
  164. package/templates/gen_ai/tsconfig.json +0 -56
  165. package/templates/gen_ai/utils/backend/base_backend/create.ts +0 -114
  166. package/templates/gen_ai/webpack.config.ts +0 -247
  167. package/templates/hello_world/canva-app.json +0 -21
  168. package/templates/hello_world/declarations/declarations.d.ts +0 -29
  169. package/templates/hello_world/eslint.config.mjs +0 -14
  170. package/templates/hello_world/package.json +0 -90
  171. package/templates/hello_world/scripts/copy_env.ts +0 -13
  172. package/templates/hello_world/scripts/ssl/ssl.ts +0 -131
  173. package/templates/hello_world/scripts/start/app_runner.ts +0 -223
  174. package/templates/hello_world/scripts/start/context.ts +0 -171
  175. package/templates/hello_world/scripts/start/start.ts +0 -46
  176. package/templates/hello_world/src/index.tsx +0 -4
  177. package/templates/hello_world/src/intents/design_editor/app.tsx +0 -86
  178. package/templates/hello_world/src/intents/design_editor/index.tsx +0 -25
  179. package/templates/hello_world/src/intents/design_editor/tests/__snapshots__/app.tests.tsx.snap +0 -45
  180. package/templates/hello_world/src/intents/design_editor/tests/app.tests.tsx +0 -92
  181. package/templates/hello_world/styles/components.css +0 -38
  182. package/templates/hello_world/tsconfig.json +0 -56
  183. package/templates/hello_world/webpack.config.ts +0 -247
  184. package/templates/mls/README.md +0 -81
  185. package/templates/mls/canva-app.json +0 -25
  186. package/templates/mls/declarations/declarations.d.ts +0 -29
  187. package/templates/mls/eslint.config.mjs +0 -14
  188. package/templates/mls/jest.config.mjs +0 -36
  189. package/templates/mls/jest.setup.ts +0 -39
  190. package/templates/mls/package.json +0 -117
  191. package/templates/mls/scripts/copy_env.ts +0 -13
  192. package/templates/mls/scripts/ssl/ssl.ts +0 -131
  193. package/templates/mls/scripts/start/app_runner.ts +0 -223
  194. package/templates/mls/scripts/start/context.ts +0 -171
  195. package/templates/mls/scripts/start/start.ts +0 -46
  196. package/templates/mls/src/__tests__/app.tests.tsx +0 -11
  197. package/templates/mls/src/__tests__/office_selection_page.tests.tsx +0 -72
  198. package/templates/mls/src/__tests__/utils.tsx +0 -19
  199. package/templates/mls/src/adapter.ts +0 -126
  200. package/templates/mls/src/components/agent/agent_card.tsx +0 -57
  201. package/templates/mls/src/components/agent/agent_grid.tsx +0 -37
  202. package/templates/mls/src/components/agent/agent_list.tsx +0 -17
  203. package/templates/mls/src/components/agent/agent_search_filters.tsx +0 -88
  204. package/templates/mls/src/components/breadcrumb/breadcrumb.tsx +0 -40
  205. package/templates/mls/src/components/listing/listing_card.tsx +0 -64
  206. package/templates/mls/src/components/listing/listing_grid.tsx +0 -37
  207. package/templates/mls/src/components/listing/listing_list.tsx +0 -21
  208. package/templates/mls/src/components/listing/listing_search_filters.tsx +0 -145
  209. package/templates/mls/src/components/placeholders/placeholders.tsx +0 -65
  210. package/templates/mls/src/data.ts +0 -359
  211. package/templates/mls/src/index.tsx +0 -4
  212. package/templates/mls/src/intents/design_editor/app.tsx +0 -44
  213. package/templates/mls/src/intents/design_editor/index.tsx +0 -25
  214. package/templates/mls/src/pages/agent_details_page/agent_details_page.tsx +0 -175
  215. package/templates/mls/src/pages/list_page/agent_tab_panel.tsx +0 -126
  216. package/templates/mls/src/pages/list_page/list_page.tsx +0 -67
  217. package/templates/mls/src/pages/list_page/listing_tab_panel.tsx +0 -135
  218. package/templates/mls/src/pages/listing_details_page/listing_details_page.tsx +0 -418
  219. package/templates/mls/src/pages/loading_page/loading_page.tsx +0 -152
  220. package/templates/mls/src/pages/office_selection_page/office_selection_page.tsx +0 -144
  221. package/templates/mls/src/real_estate.type.ts +0 -44
  222. package/templates/mls/src/util/use_add_element.tsx +0 -62
  223. package/templates/mls/src/util/use_drag_element.tsx +0 -68
  224. package/templates/mls/styles/components.css +0 -38
  225. package/templates/mls/tsconfig.json +0 -54
  226. package/templates/mls/webpack.config.ts +0 -248
  227. package/templates/optional/.cursor/mcp.json +0 -8
  228. package/templates/optional/.vscode/extensions.json +0 -6
  229. package/templates/optional/.vscode/mcp.json +0 -9
  230. package/templates/optional/AGENTS.md +0 -154
  231. package/templates/optional/CLAUDE.md +0 -154
@@ -1,126 +0,0 @@
1
- import { agents, listings } from "./data";
2
- import type { Agent, Office, Property } from "./real_estate.type";
3
-
4
- // TODO (App Developer): replace with the real API call
5
- export const fetchAgents = async (
6
- office?: Office | null,
7
- query?: string,
8
- continuation?: string,
9
- sortBy?: string,
10
- ): Promise<{ agents: Agent[]; continuation?: string }> => {
11
- // eslint-disable-next-line no-console
12
- console.log("fetchingAgents", { query, continuation, office });
13
-
14
- if (office?.id === "listings-only-office" || office?.id === "empty-office") {
15
- return { agents: [], continuation: undefined };
16
- }
17
-
18
- if (office?.id === "error-office" || query === "error") {
19
- throw new Error("Error fetching agents");
20
- }
21
- // Apply sorting
22
- if (sortBy) {
23
- const [field, direction] = sortBy.split("-");
24
-
25
- if (field === "name") {
26
- agents.sort((a, b) => {
27
- const comparison = a.name.localeCompare(b.name);
28
- return direction === "asc" ? comparison : -comparison;
29
- });
30
- }
31
- }
32
-
33
- // Simulate a delay
34
- await new Promise((resolve) => setTimeout(resolve, 10));
35
-
36
- let filteredAgents = agents;
37
-
38
- // Apply search query
39
- if (query) {
40
- filteredAgents = filteredAgents.filter(
41
- (agent) =>
42
- agent.name.toLowerCase().includes(query.toLowerCase()) ||
43
- (agent.officeId &&
44
- agent.officeId.toLowerCase().includes(query.toLowerCase())),
45
- );
46
- }
47
-
48
- if (filteredAgents.length === 0) {
49
- return { agents: [], continuation: undefined };
50
- }
51
-
52
- return {
53
- agents: filteredAgents,
54
- continuation:
55
- continuation && !query ? `${Number(continuation) + 1}` : undefined,
56
- };
57
- };
58
-
59
- // TODO (App Developer): replace with real API calls
60
- export const fetchListings = async (
61
- office?: Office | null,
62
- query?: string,
63
- propertyType?: string | null,
64
- sortBy?: string | null,
65
- continuation?: string,
66
- ): Promise<{ listings: Property[]; continuation?: string }> => {
67
- // eslint-disable-next-line no-console
68
- console.log("fetchingListings", {
69
- query,
70
- continuation,
71
- propertyType,
72
- sortBy,
73
- });
74
- // Simulate a delay
75
- await new Promise((resolve) => setTimeout(resolve, 1000));
76
-
77
- if (office?.id === "empty-office" || office?.id === "agents-only-office") {
78
- return { listings: [], continuation: undefined };
79
- }
80
-
81
- if (office?.id === "error-office" || query === "error") {
82
- throw new Error("Error fetching listings");
83
- }
84
-
85
- let filteredListings = listings;
86
-
87
- // Example filters
88
- // Apply property type filter
89
- if (propertyType) {
90
- filteredListings = filteredListings.filter(
91
- (listing) =>
92
- listing.listingType.toLowerCase() === propertyType.toLowerCase(),
93
- );
94
- }
95
-
96
- // Apply sorting filter
97
- if (sortBy) {
98
- filteredListings = [...filteredListings].sort((a, b) => {
99
- const aPrice = parseFloat(a.price.replace(/[$,]/g, ""));
100
- const bPrice = parseFloat(b.price.replace(/[$,]/g, ""));
101
- return sortBy === "price-asc" ? aPrice - bPrice : bPrice - aPrice;
102
- });
103
- }
104
-
105
- // Apply search query
106
- if (query) {
107
- filteredListings = filteredListings.filter(
108
- (listing) =>
109
- listing.address.toLowerCase().includes(query.toLowerCase()) ||
110
- listing.suburb.toLowerCase().includes(query.toLowerCase()) ||
111
- listing.description.toLowerCase().includes(query.toLowerCase()) ||
112
- listing.name.toLowerCase().includes(query.toLowerCase()) ||
113
- listing.title.toLowerCase().includes(query.toLowerCase()),
114
- );
115
- }
116
-
117
- if (filteredListings.length === 0) {
118
- return { listings: [], continuation: undefined };
119
- }
120
-
121
- return {
122
- listings: filteredListings,
123
- continuation:
124
- continuation && !query ? `${Number(continuation) + 1}` : undefined,
125
- };
126
- };
@@ -1,57 +0,0 @@
1
- import { HorizontalCard, ImageCard } from "@canva/app-ui-kit";
2
- import React from "react";
3
- import { useIntl } from "react-intl";
4
- import type { Agent } from "../../real_estate.type";
5
-
6
- interface AgentCardProps {
7
- item: Agent;
8
- onClick: (item: Agent) => void;
9
- }
10
-
11
- export const ListAgentCard: React.FC<AgentCardProps> = ({ item, onClick }) => {
12
- const intl = useIntl();
13
- const headshot = item.headshots?.[0];
14
-
15
- return (
16
- <HorizontalCard
17
- ariaLabel={item.name}
18
- title={item.name}
19
- description={item.officeId}
20
- onClick={() => onClick(item)}
21
- thumbnail={
22
- headshot
23
- ? {
24
- url: headshot.url,
25
- alt: intl.formatMessage(
26
- {
27
- defaultMessage: "Profile photo of {name}",
28
- description: "Alt text for agent profile photo",
29
- },
30
- { name: item.name },
31
- ),
32
- }
33
- : undefined
34
- }
35
- />
36
- );
37
- };
38
-
39
- export const GridAgentCard: React.FC<AgentCardProps> = ({ item, onClick }) => {
40
- const intl = useIntl();
41
-
42
- return (
43
- <ImageCard
44
- selectable
45
- thumbnailUrl={item.headshots?.[0]?.url || ""}
46
- alt={intl.formatMessage(
47
- {
48
- defaultMessage: "Profile photo of {name}",
49
- description: "Alt text for agent profile photo",
50
- },
51
- { name: item.name },
52
- )}
53
- thumbnailHeight={150}
54
- onClick={() => onClick(item)}
55
- />
56
- );
57
- };
@@ -1,37 +0,0 @@
1
- import { Column, Columns, Rows } from "@canva/app-ui-kit";
2
- import type { Agent } from "../../real_estate.type";
3
- import { GridAgentCard } from "./agent_card";
4
-
5
- interface AgentGridProps {
6
- agents: Agent[];
7
- onAgentClick: (item: Agent) => void;
8
- }
9
-
10
- export const AgentGrid = ({ agents, onAgentClick }: AgentGridProps) => {
11
- return (
12
- <Rows spacing="2u">
13
- {agents.map((item, index) => {
14
- if (index % 2 === 0) {
15
- const nextItem = agents[index + 1];
16
- return (
17
- <Columns
18
- key={`row-${Math.floor(index / 2)}`}
19
- spacing="2u"
20
- alignY="stretch"
21
- >
22
- <Column key={item.id} width="1/2">
23
- <GridAgentCard item={item} onClick={onAgentClick} />
24
- </Column>
25
- {nextItem && (
26
- <Column key={nextItem.id} width="1/2">
27
- <GridAgentCard item={nextItem} onClick={onAgentClick} />
28
- </Column>
29
- )}
30
- </Columns>
31
- );
32
- }
33
- return null;
34
- })}
35
- </Rows>
36
- );
37
- };
@@ -1,17 +0,0 @@
1
- import type { Agent } from "../../real_estate.type";
2
- import { ListAgentCard } from "./agent_card";
3
-
4
- interface AgentListProps {
5
- agents: Agent[];
6
- onAgentClick: (item: Agent) => void;
7
- }
8
-
9
- export const AgentList = ({ agents, onAgentClick }: AgentListProps) => {
10
- return (
11
- <>
12
- {agents.map((item: Agent) => (
13
- <ListAgentCard key={item.id} item={item} onClick={onAgentClick} />
14
- ))}
15
- </>
16
- );
17
- };
@@ -1,88 +0,0 @@
1
- import {
2
- Button,
3
- Column,
4
- Columns,
5
- GridViewIcon,
6
- ListBulletLtrIcon,
7
- Rows,
8
- SearchInputMenu,
9
- Select,
10
- } from "@canva/app-ui-kit";
11
- import { useState } from "react";
12
- import { useIntl } from "react-intl";
13
-
14
- type Layout = "grid" | "list";
15
-
16
- interface AgentSearchFiltersProps {
17
- query: string;
18
- onQueryChange: (query: string) => void;
19
- layout: Layout;
20
- onLayoutToggle: () => void;
21
- sort: string;
22
- onSortChange: (sort: string) => void;
23
- }
24
-
25
- export const AgentSearchFilters = ({
26
- query,
27
- onQueryChange,
28
- layout,
29
- onLayoutToggle,
30
- sort,
31
- onSortChange,
32
- }: AgentSearchFiltersProps) => {
33
- const intl = useIntl();
34
- const [queryValue, setQueryValue] = useState(query);
35
- return (
36
- <Rows spacing="2u">
37
- <SearchInputMenu
38
- value={queryValue}
39
- onChange={setQueryValue}
40
- onChangeComplete={() => onQueryChange(queryValue)}
41
- onClear={() => {
42
- setQueryValue("");
43
- onQueryChange("");
44
- }}
45
- placeholder={intl.formatMessage({
46
- defaultMessage: "Search agents...",
47
- description: "Placeholder text for agents search input",
48
- })}
49
- />
50
- <Columns spacing="1u" alignY="center">
51
- <Column width="content">
52
- <Button
53
- icon={layout === "grid" ? GridViewIcon : ListBulletLtrIcon}
54
- type="button"
55
- onClick={onLayoutToggle}
56
- variant="secondary"
57
- />
58
- </Column>
59
- <Column width="1/3">
60
- <Select
61
- value={sort}
62
- onChange={onSortChange}
63
- options={[
64
- {
65
- label: intl.formatMessage({
66
- defaultMessage: "Name: A to Z",
67
- description: "Sort option - name ascending",
68
- }),
69
- value: "name-asc",
70
- },
71
- {
72
- label: intl.formatMessage({
73
- defaultMessage: "Name: Z to A",
74
- description: "Sort option - name descending",
75
- }),
76
- value: "name-desc",
77
- },
78
- ]}
79
- placeholder={intl.formatMessage({
80
- defaultMessage: "Sort by",
81
- description: "Placeholder text for agents sort dropdown",
82
- })}
83
- />
84
- </Column>
85
- </Columns>
86
- </Rows>
87
- );
88
- };
@@ -1,40 +0,0 @@
1
- import {
2
- ArrowLeftIcon,
3
- Button,
4
- Column,
5
- Columns,
6
- Text,
7
- } from "@canva/app-ui-kit";
8
- import { useIntl } from "react-intl";
9
- import { useLocation, useNavigate } from "react-router-dom";
10
- import type { Office } from "../../real_estate.type";
11
-
12
- export const Breadcrumb = () => {
13
- const office = (useLocation().state as { office: Office })?.office;
14
- const navigate = useNavigate();
15
- const intl = useIntl();
16
-
17
- return (
18
- <Columns spacing="1u" alignY="center">
19
- <Column width="content">
20
- <Button
21
- icon={ArrowLeftIcon}
22
- size="small"
23
- type="button"
24
- variant="tertiary"
25
- onClick={() => navigate("/entry")}
26
- />
27
- </Column>
28
- <Column>
29
- <Text variant="bold">
30
- {office
31
- ? office.name
32
- : intl.formatMessage({
33
- defaultMessage: "Back",
34
- description: "Back button",
35
- })}
36
- </Text>
37
- </Column>
38
- </Columns>
39
- );
40
- };
@@ -1,64 +0,0 @@
1
- import { HorizontalCard, ImageCard, Rows, Text } from "@canva/app-ui-kit";
2
- import type { Property } from "../../real_estate.type";
3
-
4
- export interface ListingCardProps<T extends Property> {
5
- item: T;
6
- onClick?: (item: T) => void;
7
- }
8
-
9
- interface BaseListingCardProps<T extends Property> {
10
- item: T;
11
- onClick?: (item: T) => void;
12
- }
13
-
14
- export const GridListingCard = <T extends Property>({
15
- item,
16
- onClick,
17
- }: BaseListingCardProps<T>) => {
18
- const handleClick = () => {
19
- onClick?.(item);
20
- };
21
-
22
- return (
23
- <div>
24
- <Rows spacing="1u">
25
- <ImageCard
26
- selectable
27
- thumbnailUrl={item.thumbnail.url}
28
- alt={item.description}
29
- borderRadius="standard"
30
- onClick={handleClick}
31
- thumbnailHeight={110}
32
- />
33
- <Rows spacing="0">
34
- <Text variant="bold" lineClamp={1}>
35
- {item.title}
36
- </Text>
37
- {item.suburb && <Text size="small">{item.suburb}</Text>}
38
- </Rows>
39
- </Rows>
40
- </div>
41
- );
42
- };
43
-
44
- export const ListListingCard = <T extends Property>({
45
- item,
46
- onClick,
47
- }: BaseListingCardProps<T>) => {
48
- const handleClick = () => {
49
- onClick?.(item);
50
- };
51
-
52
- return (
53
- <HorizontalCard
54
- ariaLabel={item.title}
55
- title={item.title}
56
- description={item.suburb}
57
- onClick={handleClick}
58
- thumbnail={{
59
- url: item.thumbnail.url,
60
- alt: item.description,
61
- }}
62
- />
63
- );
64
- };
@@ -1,37 +0,0 @@
1
- import { Column, Columns, Rows } from "@canva/app-ui-kit";
2
- import type { Property } from "../../real_estate.type";
3
- import { GridListingCard } from "./listing_card";
4
-
5
- interface ListingGridProps {
6
- listings: Property[];
7
- onListingClick: (item: Property) => void;
8
- }
9
-
10
- export const ListingGrid = ({ listings, onListingClick }: ListingGridProps) => {
11
- return (
12
- <Rows spacing="2u">
13
- {listings.map((item, index) => {
14
- if (index % 2 === 0) {
15
- const nextItem = listings[index + 1];
16
- return (
17
- <Columns
18
- key={`row-${Math.floor(index / 2)}`}
19
- spacing="2u"
20
- alignY="stretch"
21
- >
22
- <Column key={item.id} width="1/2">
23
- <GridListingCard item={item} onClick={onListingClick} />
24
- </Column>
25
- {nextItem && (
26
- <Column key={nextItem.id} width="1/2">
27
- <GridListingCard item={nextItem} onClick={onListingClick} />
28
- </Column>
29
- )}
30
- </Columns>
31
- );
32
- }
33
- return null;
34
- })}
35
- </Rows>
36
- );
37
- };
@@ -1,21 +0,0 @@
1
- import type { Property } from "../../real_estate.type";
2
- import { ListListingCard } from "./listing_card";
3
-
4
- interface ListingListProps {
5
- listings: Property[];
6
- onListingClick: (item: Property) => void;
7
- }
8
-
9
- export const ListingList = ({ listings, onListingClick }: ListingListProps) => {
10
- return (
11
- <>
12
- {listings.map((item: Property, index: number) => (
13
- <ListListingCard
14
- key={`${item.id}-${index}`}
15
- item={item}
16
- onClick={onListingClick}
17
- />
18
- ))}
19
- </>
20
- );
21
- };
@@ -1,145 +0,0 @@
1
- import {
2
- Button,
3
- Column,
4
- Columns,
5
- GridViewIcon,
6
- ListBulletLtrIcon,
7
- Rows,
8
- SearchInputMenu,
9
- Select,
10
- } from "@canva/app-ui-kit";
11
- import { useState } from "react";
12
- import { useIntl } from "react-intl";
13
-
14
- type Layout = "grid" | "list";
15
-
16
- interface ListingSearchFiltersProps {
17
- query: string;
18
- onQueryChange: (query: string) => void;
19
- layout: Layout;
20
- onLayoutToggle: () => void;
21
- propertyType: string;
22
- onPropertyTypeChange: (type: string) => void;
23
- sort: string;
24
- onSortChange: (sort: string) => void;
25
- }
26
-
27
- export const ListingSearchFilters = ({
28
- query,
29
- onQueryChange,
30
- layout,
31
- onLayoutToggle,
32
- propertyType,
33
- onPropertyTypeChange,
34
- sort,
35
- onSortChange,
36
- }: ListingSearchFiltersProps) => {
37
- const intl = useIntl();
38
- const [queryValue, setQueryValue] = useState(query);
39
- return (
40
- <Rows spacing="2u">
41
- <SearchInputMenu
42
- value={queryValue}
43
- onChange={setQueryValue}
44
- onChangeComplete={() => onQueryChange(queryValue)}
45
- onClear={() => {
46
- setQueryValue("");
47
- onQueryChange("");
48
- }}
49
- placeholder={intl.formatMessage({
50
- defaultMessage: "Search listings...",
51
- description: "Placeholder text for listings search input",
52
- })}
53
- />
54
- <Columns spacing="1u" alignY="center">
55
- <Column width="content">
56
- <Button
57
- icon={layout === "grid" ? GridViewIcon : ListBulletLtrIcon}
58
- type="button"
59
- onClick={onLayoutToggle}
60
- variant="secondary"
61
- ariaLabel={intl.formatMessage(
62
- {
63
- defaultMessage:
64
- "Toggle layout between grid and list. Current layout is {currentLayout}",
65
- description: "Aria label for layout toggle button",
66
- },
67
- {
68
- currentLayout:
69
- layout === "grid"
70
- ? intl.formatMessage({
71
- defaultMessage: "grid",
72
- description: "Layout option",
73
- })
74
- : intl.formatMessage({
75
- defaultMessage: "list",
76
- description: "Layout option",
77
- }),
78
- },
79
- )}
80
- />
81
- </Column>
82
- <Column width="1/3">
83
- {/* TODO (App Developer): Review filter options and update to match your specific property data shape */}
84
- <Select
85
- value={propertyType}
86
- onChange={onPropertyTypeChange}
87
- options={[
88
- {
89
- label: intl.formatMessage({
90
- defaultMessage: "House",
91
- description: "Property type option - house",
92
- }),
93
- value: "house",
94
- },
95
- {
96
- label: intl.formatMessage({
97
- defaultMessage: "Apartment",
98
- description: "Property type option - apartment",
99
- }),
100
- value: "apartment",
101
- },
102
- {
103
- label: intl.formatMessage({
104
- defaultMessage: "Townhouse",
105
- description: "Property type option - townhouse",
106
- }),
107
- value: "townhouse",
108
- },
109
- ]}
110
- placeholder={intl.formatMessage({
111
- defaultMessage: "Property type",
112
- description: "Placeholder text for property type dropdown",
113
- })}
114
- />
115
- </Column>
116
- <Column width="1/3">
117
- <Select
118
- value={sort}
119
- onChange={onSortChange}
120
- options={[
121
- {
122
- label: intl.formatMessage({
123
- defaultMessage: "Price: Low to High",
124
- description: "Sort option - price ascending",
125
- }),
126
- value: "price-asc",
127
- },
128
- {
129
- label: intl.formatMessage({
130
- defaultMessage: "Price: High to Low",
131
- description: "Sort option - price descending",
132
- }),
133
- value: "price-desc",
134
- },
135
- ]}
136
- placeholder={intl.formatMessage({
137
- defaultMessage: "Sort by",
138
- description: "Placeholder text for sort dropdown",
139
- })}
140
- />
141
- </Column>
142
- </Columns>
143
- </Rows>
144
- );
145
- };