@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.
- package/CHANGELOG.md +26 -0
- package/README.md +1 -9
- package/cli.js +625 -626
- package/package.json +2 -3
- package/templates/base/backend/base_backend/create.ts +0 -114
- package/templates/base/backend/database/database.ts +0 -42
- package/templates/base/backend/routers/auth.ts +0 -288
- package/templates/base/declarations/declarations.d.ts +0 -29
- package/templates/base/eslint.config.mjs +0 -14
- package/templates/base/package.json +0 -91
- package/templates/base/scripts/copy_env.ts +0 -13
- package/templates/base/scripts/ssl/ssl.ts +0 -131
- package/templates/base/scripts/start/app_runner.ts +0 -223
- package/templates/base/scripts/start/context.ts +0 -171
- package/templates/base/scripts/start/start.ts +0 -46
- package/templates/base/scripts/start.tests.ts +0 -61
- package/templates/base/styles/components.css +0 -38
- package/templates/base/tsconfig.json +0 -56
- package/templates/base/webpack.config.ts +0 -247
- package/templates/common/.env.template +0 -6
- package/templates/common/.gitignore.template +0 -8
- package/templates/common/.nvmrc +0 -1
- package/templates/common/.prettierrc +0 -21
- package/templates/common/LICENSE.md +0 -48
- package/templates/common/README.md +0 -179
- package/templates/common/jest.config.mjs +0 -35
- package/templates/common/jest.setup.ts +0 -35
- package/templates/content_publisher/README.md +0 -58
- package/templates/content_publisher/canva-app.json +0 -17
- package/templates/content_publisher/declarations/declarations.d.ts +0 -29
- package/templates/content_publisher/eslint.config.mjs +0 -14
- package/templates/content_publisher/package.json +0 -90
- package/templates/content_publisher/scripts/copy_env.ts +0 -13
- package/templates/content_publisher/scripts/ssl/ssl.ts +0 -131
- package/templates/content_publisher/scripts/start/app_runner.ts +0 -223
- package/templates/content_publisher/scripts/start/context.ts +0 -171
- package/templates/content_publisher/scripts/start/start.ts +0 -46
- package/templates/content_publisher/src/index.tsx +0 -4
- package/templates/content_publisher/src/intents/content_publisher/index.tsx +0 -107
- package/templates/content_publisher/src/intents/content_publisher/post_preview.tsx +0 -240
- package/templates/content_publisher/src/intents/content_publisher/preview_ui.tsx +0 -62
- package/templates/content_publisher/src/intents/content_publisher/settings_ui.tsx +0 -81
- package/templates/content_publisher/src/intents/content_publisher/types.ts +0 -29
- package/templates/content_publisher/styles/components.css +0 -38
- package/templates/content_publisher/styles/preview_ui.css +0 -49
- package/templates/content_publisher/tsconfig.json +0 -56
- package/templates/content_publisher/webpack.config.ts +0 -247
- package/templates/dam/backend/routers/dam.ts +0 -108
- package/templates/dam/backend/server.ts +0 -65
- package/templates/dam/canva-app.json +0 -25
- package/templates/dam/declarations/declarations.d.ts +0 -29
- package/templates/dam/eslint.config.mjs +0 -14
- package/templates/dam/package.json +0 -97
- package/templates/dam/scripts/copy_env.ts +0 -13
- package/templates/dam/scripts/ssl/ssl.ts +0 -131
- package/templates/dam/scripts/start/app_runner.ts +0 -223
- package/templates/dam/scripts/start/context.ts +0 -171
- package/templates/dam/scripts/start/start.ts +0 -46
- package/templates/dam/src/index.tsx +0 -4
- package/templates/dam/src/intents/design_editor/adapter.ts +0 -44
- package/templates/dam/src/intents/design_editor/app.tsx +0 -35
- package/templates/dam/src/intents/design_editor/config.ts +0 -220
- package/templates/dam/src/intents/design_editor/index.css +0 -3
- package/templates/dam/src/intents/design_editor/index.tsx +0 -25
- package/templates/dam/tsconfig.json +0 -56
- package/templates/dam/utils/backend/base_backend/create.ts +0 -114
- package/templates/dam/webpack.config.ts +0 -247
- package/templates/data_connector/README.md +0 -84
- package/templates/data_connector/canva-app.json +0 -21
- package/templates/data_connector/declarations/declarations.d.ts +0 -29
- package/templates/data_connector/eslint.config.mjs +0 -14
- package/templates/data_connector/package.json +0 -92
- package/templates/data_connector/scripts/copy_env.ts +0 -13
- package/templates/data_connector/scripts/ssl/ssl.ts +0 -131
- package/templates/data_connector/scripts/start/app_runner.ts +0 -223
- package/templates/data_connector/scripts/start/context.ts +0 -171
- package/templates/data_connector/scripts/start/start.ts +0 -46
- package/templates/data_connector/src/api/connect_client.ts +0 -6
- package/templates/data_connector/src/api/data_source.ts +0 -97
- package/templates/data_connector/src/api/data_sources/designs.tsx +0 -296
- package/templates/data_connector/src/api/data_sources/index.ts +0 -4
- package/templates/data_connector/src/api/data_sources/templates.tsx +0 -328
- package/templates/data_connector/src/api/fetch_data_table.ts +0 -55
- package/templates/data_connector/src/api/index.ts +0 -4
- package/templates/data_connector/src/api/oauth.ts +0 -8
- package/templates/data_connector/src/api/tests/data_source.test.tsx +0 -99
- package/templates/data_connector/src/components/app_error.tsx +0 -15
- package/templates/data_connector/src/components/footer.tsx +0 -26
- package/templates/data_connector/src/components/header.tsx +0 -40
- package/templates/data_connector/src/components/index.ts +0 -3
- package/templates/data_connector/src/components/inputs/messages.tsx +0 -95
- package/templates/data_connector/src/components/inputs/search_filter.tsx +0 -109
- package/templates/data_connector/src/components/inputs/select_field.tsx +0 -26
- package/templates/data_connector/src/context/app_context.tsx +0 -125
- package/templates/data_connector/src/context/index.ts +0 -2
- package/templates/data_connector/src/context/use_app_context.ts +0 -17
- package/templates/data_connector/src/index.tsx +0 -4
- package/templates/data_connector/src/intents/data_connector/app.tsx +0 -20
- package/templates/data_connector/src/intents/data_connector/entrypoint.tsx +0 -70
- package/templates/data_connector/src/intents/data_connector/home.tsx +0 -21
- package/templates/data_connector/src/intents/data_connector/index.tsx +0 -56
- package/templates/data_connector/src/pages/data_source_config.tsx +0 -9
- package/templates/data_connector/src/pages/error.tsx +0 -37
- package/templates/data_connector/src/pages/index.ts +0 -4
- package/templates/data_connector/src/pages/login.tsx +0 -145
- package/templates/data_connector/src/pages/select_source.tsx +0 -24
- package/templates/data_connector/src/routes/index.ts +0 -2
- package/templates/data_connector/src/routes/paths.ts +0 -7
- package/templates/data_connector/src/routes/protected_route.tsx +0 -26
- package/templates/data_connector/src/routes/routes.tsx +0 -42
- package/templates/data_connector/src/utils/data_params.ts +0 -17
- package/templates/data_connector/src/utils/data_table.ts +0 -116
- package/templates/data_connector/src/utils/fetch_result.ts +0 -36
- package/templates/data_connector/src/utils/index.ts +0 -2
- package/templates/data_connector/src/utils/tests/data_table.test.ts +0 -133
- package/templates/data_connector/styles/components.css +0 -38
- package/templates/data_connector/tsconfig.json +0 -56
- package/templates/data_connector/webpack.config.ts +0 -247
- package/templates/gen_ai/README.md +0 -27
- package/templates/gen_ai/backend/routers/image.ts +0 -232
- package/templates/gen_ai/backend/server.ts +0 -65
- package/templates/gen_ai/canva-app.json +0 -25
- package/templates/gen_ai/declarations/declarations.d.ts +0 -29
- package/templates/gen_ai/eslint.config.mjs +0 -14
- package/templates/gen_ai/package.json +0 -101
- package/templates/gen_ai/scripts/copy_env.ts +0 -13
- package/templates/gen_ai/scripts/ssl/ssl.ts +0 -131
- package/templates/gen_ai/scripts/start/app_runner.ts +0 -223
- package/templates/gen_ai/scripts/start/context.ts +0 -171
- package/templates/gen_ai/scripts/start/start.ts +0 -46
- package/templates/gen_ai/src/api/api.ts +0 -194
- package/templates/gen_ai/src/api/index.ts +0 -1
- package/templates/gen_ai/src/components/app_error.tsx +0 -18
- package/templates/gen_ai/src/components/footer.messages.ts +0 -48
- package/templates/gen_ai/src/components/footer.tsx +0 -156
- package/templates/gen_ai/src/components/image_grid.tsx +0 -103
- package/templates/gen_ai/src/components/index.ts +0 -7
- package/templates/gen_ai/src/components/loading_results.tsx +0 -169
- package/templates/gen_ai/src/components/prompt_input.messages.ts +0 -14
- package/templates/gen_ai/src/components/prompt_input.tsx +0 -154
- package/templates/gen_ai/src/components/remaining_credits.tsx +0 -84
- package/templates/gen_ai/src/components/report_box.tsx +0 -54
- package/templates/gen_ai/src/components/tests/remaining_credit.tests.tsx +0 -47
- package/templates/gen_ai/src/config.ts +0 -21
- package/templates/gen_ai/src/context/app_context.tsx +0 -153
- package/templates/gen_ai/src/context/context.messages.ts +0 -30
- package/templates/gen_ai/src/context/index.ts +0 -2
- package/templates/gen_ai/src/context/use_app_context.ts +0 -17
- package/templates/gen_ai/src/index.tsx +0 -4
- package/templates/gen_ai/src/intents/design_editor/app.tsx +0 -19
- package/templates/gen_ai/src/intents/design_editor/home.tsx +0 -13
- package/templates/gen_ai/src/intents/design_editor/index.tsx +0 -17
- package/templates/gen_ai/src/pages/error.tsx +0 -41
- package/templates/gen_ai/src/pages/generate.tsx +0 -9
- package/templates/gen_ai/src/pages/index.ts +0 -3
- package/templates/gen_ai/src/pages/results.tsx +0 -31
- package/templates/gen_ai/src/routes/index.ts +0 -1
- package/templates/gen_ai/src/routes/paths.ts +0 -4
- package/templates/gen_ai/src/routes/routes.tsx +0 -24
- package/templates/gen_ai/src/utils/index.ts +0 -1
- package/templates/gen_ai/src/utils/obscenity_filter.ts +0 -33
- package/templates/gen_ai/styles/components.css +0 -38
- package/templates/gen_ai/styles/utils.css +0 -3
- package/templates/gen_ai/tsconfig.json +0 -56
- package/templates/gen_ai/utils/backend/base_backend/create.ts +0 -114
- package/templates/gen_ai/webpack.config.ts +0 -247
- package/templates/hello_world/canva-app.json +0 -21
- package/templates/hello_world/declarations/declarations.d.ts +0 -29
- package/templates/hello_world/eslint.config.mjs +0 -14
- package/templates/hello_world/package.json +0 -90
- package/templates/hello_world/scripts/copy_env.ts +0 -13
- package/templates/hello_world/scripts/ssl/ssl.ts +0 -131
- package/templates/hello_world/scripts/start/app_runner.ts +0 -223
- package/templates/hello_world/scripts/start/context.ts +0 -171
- package/templates/hello_world/scripts/start/start.ts +0 -46
- package/templates/hello_world/src/index.tsx +0 -4
- package/templates/hello_world/src/intents/design_editor/app.tsx +0 -86
- package/templates/hello_world/src/intents/design_editor/index.tsx +0 -25
- package/templates/hello_world/src/intents/design_editor/tests/__snapshots__/app.tests.tsx.snap +0 -45
- package/templates/hello_world/src/intents/design_editor/tests/app.tests.tsx +0 -92
- package/templates/hello_world/styles/components.css +0 -38
- package/templates/hello_world/tsconfig.json +0 -56
- package/templates/hello_world/webpack.config.ts +0 -247
- package/templates/mls/README.md +0 -81
- package/templates/mls/canva-app.json +0 -25
- package/templates/mls/declarations/declarations.d.ts +0 -29
- package/templates/mls/eslint.config.mjs +0 -14
- package/templates/mls/jest.config.mjs +0 -36
- package/templates/mls/jest.setup.ts +0 -39
- package/templates/mls/package.json +0 -117
- package/templates/mls/scripts/copy_env.ts +0 -13
- package/templates/mls/scripts/ssl/ssl.ts +0 -131
- package/templates/mls/scripts/start/app_runner.ts +0 -223
- package/templates/mls/scripts/start/context.ts +0 -171
- package/templates/mls/scripts/start/start.ts +0 -46
- package/templates/mls/src/__tests__/app.tests.tsx +0 -11
- package/templates/mls/src/__tests__/office_selection_page.tests.tsx +0 -72
- package/templates/mls/src/__tests__/utils.tsx +0 -19
- package/templates/mls/src/adapter.ts +0 -126
- package/templates/mls/src/components/agent/agent_card.tsx +0 -57
- package/templates/mls/src/components/agent/agent_grid.tsx +0 -37
- package/templates/mls/src/components/agent/agent_list.tsx +0 -17
- package/templates/mls/src/components/agent/agent_search_filters.tsx +0 -88
- package/templates/mls/src/components/breadcrumb/breadcrumb.tsx +0 -40
- package/templates/mls/src/components/listing/listing_card.tsx +0 -64
- package/templates/mls/src/components/listing/listing_grid.tsx +0 -37
- package/templates/mls/src/components/listing/listing_list.tsx +0 -21
- package/templates/mls/src/components/listing/listing_search_filters.tsx +0 -145
- package/templates/mls/src/components/placeholders/placeholders.tsx +0 -65
- package/templates/mls/src/data.ts +0 -359
- package/templates/mls/src/index.tsx +0 -4
- package/templates/mls/src/intents/design_editor/app.tsx +0 -44
- package/templates/mls/src/intents/design_editor/index.tsx +0 -25
- package/templates/mls/src/pages/agent_details_page/agent_details_page.tsx +0 -175
- package/templates/mls/src/pages/list_page/agent_tab_panel.tsx +0 -126
- package/templates/mls/src/pages/list_page/list_page.tsx +0 -67
- package/templates/mls/src/pages/list_page/listing_tab_panel.tsx +0 -135
- package/templates/mls/src/pages/listing_details_page/listing_details_page.tsx +0 -418
- package/templates/mls/src/pages/loading_page/loading_page.tsx +0 -152
- package/templates/mls/src/pages/office_selection_page/office_selection_page.tsx +0 -144
- package/templates/mls/src/real_estate.type.ts +0 -44
- package/templates/mls/src/util/use_add_element.tsx +0 -62
- package/templates/mls/src/util/use_drag_element.tsx +0 -68
- package/templates/mls/styles/components.css +0 -38
- package/templates/mls/tsconfig.json +0 -54
- package/templates/mls/webpack.config.ts +0 -248
- package/templates/optional/.cursor/mcp.json +0 -8
- package/templates/optional/.vscode/extensions.json +0 -6
- package/templates/optional/.vscode/mcp.json +0 -9
- package/templates/optional/AGENTS.md +0 -154
- 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
|
-
};
|