import { LitElement, html, css, svg, TemplateResult } from "lit"; import { customElement, property, state, query } from "lit/decorators.js"; import { ifDefined } from "lit/directives/if-defined.js"; import { Nonprofit, ChangeSearchBar } from "./change-search-bar"; import "./change-search-bar"; import "./change-donation-form"; @customElement("change-drop-in") export class ChangeDropIn extends LitElement { @property({ type: Array, attribute: "featured-nonprofits" }) featuredNonprofitIds = []; @property({ type: String, attribute: "public-key" }) publicKey?: string; @property() title: string = "Support a cause"; @state() featuredNonprofits: Nonprofit[] = []; @state() view: "featured" | "cause" = "featured"; @state() selectedNonprofit?: Nonprofit; @query("change-search-bar") changeSearchBar!: ChangeSearchBar; constructor() { super(); this.addEventListener("select-nonprofit", ((e: CustomEvent) => { this.handleSelectNonprofit(e.detail as Nonprofit); this.changeSearchBar.clear(); }) as EventListener); } firstUpdated() { fetchNonprofits(this.featuredNonprofitIds).then( (nonprofits) => (this.featuredNonprofits = nonprofits.slice(0, 4)) ); } render() { return html`

${this.title}

${this.view === "featured" ? this.renderFeaturedGrid() : this.renderCause()}
`; } renderFeaturedGrid() { return html` `; } renderCause() { return html`
${this.selectedNonprofit?.name}
${this.selectedNonprofit?.category}
Mission
${this.selectedNonprofit?.description}
ein
${this.selectedNonprofit?.ein.slice( 0, 2 )}-${this.selectedNonprofit?.ein.slice(2)}
`; } private handleSelectNonprofit(nonprofit: Nonprofit) { this.selectedNonprofit = nonprofit; this.view = "cause"; } static styles = css` :host { display: block; max-width: 800px; font-family: sans-serif; background-color: var(--background-color, #f7f9fa); color: var(--color, black); padding: 1em; } #container { display: flex; flex-direction: column; align-items: center; } change-search-bar { width: 100%; } #featured-grid { display: flex; flex-wrap: wrap; width: 40em; max-width: 100%; margin-top: 1em; } .featured-nonprofit { display: flex; flex-direction: column; justify-content: flex-start; box-shadow: 0px 0px 21px rgba(0, 0, 0, 0.04); border-radius: 1em; padding: 1em; background-color: var(--card-background-color, white); flex: 1; min-width: 15em; max-width: 100%; margin: 1em; text-align: left; } .featured-nonprofit .arrow { display: inline-block; opacity: 0; transform: translateX(-0.1em); transition: all 0.1s ease-out; } .featured-nonprofit:hover .arrow { opacity: 1; transform: translateX(0); } .featured-nonprofit .arrow svg { line-height: 0; height: 0.9em; width: 0.9em; top: 2px; vertical-align: -2px; transform: rotate(180deg); } .top-bar { display: flex; align-items: center; margin-bottom: 1em; } .top-bar > img { width: 3em; margin-right: 1em; border-radius: 50%; align-self: center; } .top-bar > div { flex: 1; } .name { font-weight: 700; margin-bottom: 0.2em; } .category { color: #aaa; } #cause-view { display: flex; justify-content: center; flex-wrap: wrap; padding: 1em; } #cause-view > div { padding: 1.5em; flex: 1; min-width: 15em; } #back-button { display: flex; align-items: center; color: var(--detail-color, #999); margin-bottom: 1em; } #back-button svg { margin-right: 0.2em; } #cause-view .title { text-transform: uppercase; font-size: 0.8em; font-weight: 700; color: var(--detail-color, #999); margin-top: 2em; margin-bottom: 0.2em; } change-donation-form { --background-color: var(--card-background-color, white); border-radius: 1em; flex: 1; } button { font-size: inherit; color: inherit; border: none; cursor: pointer; background: none; } `; } async function fetchNonprofits(ids: string[]) { const params = new URLSearchParams(); for (const id of ids) { params.append("ids[]", id); } return fetch( `https://api.getchange.io/api/v1/nonprofit_basics?${params.toString()}` ) .then((response) => response.json()) .then((response) => response.nonprofits as Nonprofit[]); } function backIcon() { return svg` `; } function postFixWithNonbreakingSpace(phrase: string, item: TemplateResult) { const words = phrase.split(" "); const allButFirst = words.slice(0, words.length - 1); const last = words[words.length - 1]; // The extra ensures the space between all but the first and the last word // doesn't get minified out in the production build. return html`${allButFirst.join(" ")}
${last} ${item}
`; }