Skip to content

Commit

Permalink
initial commit of new implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
brianflanagan committed Jan 4, 2025
1 parent 53a4632 commit d7a0aa3
Show file tree
Hide file tree
Showing 113 changed files with 1,902 additions and 2,322 deletions.
59 changes: 59 additions & 0 deletions .github/workflows/elixir.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: CI

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
test:
runs-on: ubuntu-latest

services:
postgres:
image: postgres:13
ports:
- 5432:5432
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: ppr_api_test
options: >-
--health-cmd "pg_isready -U postgres"
--health-interval 10s
--health-timeout 5s
--health-retries 5
strategy:
matrix:
elixir: [1.13.4, 1.14.3]
otp: [24.3, 25.1]

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Set up Elixir
uses: erlef/setup-beam@v1
with:
elixir-version: ${{ matrix.elixir }}
otp-version: ${{ matrix.otp }}

- name: Install dependencies
run: mix deps.get

- name: Set up the database
run: |
mix ecto.create
mix ecto.migrate
env:
MIX_ENV: test
DATABASE_URL: ecto://postgres:postgres@localhost/ppr_api_test

- name: Run tests
run: mix test
env:
MIX_ENV: test
16 changes: 5 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@ There are a bunch of caveats about the data on the <a href="https://www.property

The API only covers residential properties. Maybe you want to add commercial properties? <a href="https://www.github.com/civictech-ie/price-register">Go ahead</a>.

I made a public site primarily to illustrate how one might interact with this API. It&rsquo;s generally what you'd expect, I hope. <code>GET /api/sales</code> will return a list of JSON objects. <code>GET /api/sales/:id</code> will return a single JSON sale object. The <code>:id</code> is a uuid, so it's not guessable – you'll need to <code>GET /api/sales</code> to find them.

At the moment, the list endpoint only takes <code>before</code> or <code>after</code> params to page around &mdash; no filtering or sorting yet. If you want to do that, you can page through the sales and ingest them into your own database. And then go wild. You do you.
I made a public site primarily to illustrate how one might interact with this API. It&rsquo;s generally what you'd expect, I hope. <code>GET /api/v1/residential/sales</code> will return a list of JSON objects.

## development

It's pretty straightforward to run the app yourself. It's a typical [Elixir](https://elixir-lang.org)/[Phoenix](https://www.phoenixframework.org) app with a GenServer for polling and consuming the CSVs from the PSRA.
It's pretty straightforward to run the app yourself. It's a typical [Elixir](https://elixir-lang.org)/[Phoenix](https://www.phoenixframework.org) app that fetches and consumes CSVs from the PSRA.

You'll need Elixir and PostgreSQL installed.
You'll need Elixir, Erlang and PostgreSQL installed.

```
git clone https://github.com/civictech-ie/price-register.git
Expand All @@ -24,14 +22,10 @@ mix ecto.setup
mix phx.server
```

Now you can visit [`localhost:4000`](http://localhost:4000) and it should be working.

## deployment

It's deployed at [Render](https://www.render.com) and I'll keep an eye to make sure it can handle the load the API is getting. If you're planning on making a ton of requests (eg querying directly from a popular client-side app), you might give me a heads up, or, better yet, set up your own deployment. It's very easy...
Now you can visit [`localhost:4000`](http://localhost:4000) and it should be working. It might run a bit hot while it does its initial fetch from the PSRA.

## contributing

If you're interested in contributing, put a note [in the issues](https://github.com/civictech-ie/price-register/issues). And make sure the tests pass (`mix test`).

In general, I'm thinking the scope is: let's make the API a bit better for querying and ordering results. But making the public site much better is out of scope – if you want to do that, just make your own service that consumes this API!
In general, I'm thinking the scope is: let's make the API a bit better for querying and ordering results. But making the public site much better is out of scope – if you want to do that, just make your own service that consumes this API!
136 changes: 4 additions & 132 deletions assets/css/app.css
Original file line number Diff line number Diff line change
@@ -1,133 +1,5 @@
/* This file is for your main application CSS */

// reset

@viewport {
zoom: 1;
width: extend-to-zoom;
}

@-ms-viewport {
width: extend-to-zoom;
zoom: 1;
}

html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
font,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td {
margin: 0;
padding: 0;
font-size: 100%;
vertical-align: baseline;
border: 0;
background: transparent;
font-feature-settings: "kern", "liga", "pnum";
-webkit-backface-visibility: visible;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
text-size-adjust: 100%;
}

blockquote,
q {
quotes: none;
}

table {
border-collapse: collapse;
border-spacing: 0;
}
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

ul,
ol {
list-style: none;
}

* {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
}

// styles

html {
font-size: 10px;
--accent: #ff4400;
--background: #fafafa;
--ink: #000;
--offset: #eee;
}

body {
background-color: var(--background);
color: var(--ink);
font-size: 1.1rem;
line-height: 2rem;
font-family: "Inter", serif;
}

::selection {
color: var(--accent);
background: var(--offset);
}
/* This file is for your main application CSS */
9 changes: 6 additions & 3 deletions assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,15 @@ import {LiveSocket} from "phoenix_live_view"
import topbar from "../vendor/topbar"

let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}})
let liveSocket = new LiveSocket("/live", Socket, {
longPollFallbackMs: 2500,
params: {_csrf_token: csrfToken}
})

// Show progress bar on live navigation and form submits
topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"})
window.addEventListener("phx:page-loading-start", info => topbar.delayedShow(200))
window.addEventListener("phx:page-loading-stop", info => topbar.hide())
window.addEventListener("phx:page-loading-start", _info => topbar.show(300))
window.addEventListener("phx:page-loading-stop", _info => topbar.hide())

// connect if there are any LiveViews on the page
liveSocket.connect()
Expand Down
58 changes: 53 additions & 5 deletions assets/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
// https://tailwindcss.com/docs/configuration

const plugin = require("tailwindcss/plugin")
const fs = require("fs")
const path = require("path")

module.exports = {
content: [
"./js/**/*.js",
"../lib/*_web.ex",
"../lib/*_web/**/*.*ex"
"../lib/ppr_api_web.ex",
"../lib/ppr_api_web/**/*.*ex"
],
theme: {
extend: {
Expand All @@ -18,9 +20,55 @@ module.exports = {
},
plugins: [
require("@tailwindcss/forms"),
plugin(({addVariant}) => addVariant("phx-no-feedback", [".phx-no-feedback&", ".phx-no-feedback &"])),
// Allows prefixing tailwind classes with LiveView classes to add rules
// only when LiveView classes are applied, for example:
//
// <div class="phx-click-loading:animate-ping">
//
plugin(({addVariant}) => addVariant("phx-click-loading", [".phx-click-loading&", ".phx-click-loading &"])),
plugin(({addVariant}) => addVariant("phx-submit-loading", [".phx-submit-loading&", ".phx-submit-loading &"])),
plugin(({addVariant}) => addVariant("phx-change-loading", [".phx-change-loading&", ".phx-change-loading &"]))
plugin(({addVariant}) => addVariant("phx-change-loading", [".phx-change-loading&", ".phx-change-loading &"])),

// Embeds Heroicons (https://heroicons.com) into your app.css bundle
// See your `CoreComponents.icon/1` for more information.
//
plugin(function({matchComponents, theme}) {
let iconsDir = path.join(__dirname, "../deps/heroicons/optimized")
let values = {}
let icons = [
["", "/24/outline"],
["-solid", "/24/solid"],
["-mini", "/20/solid"],
["-micro", "/16/solid"]
]
icons.forEach(([suffix, dir]) => {
fs.readdirSync(path.join(iconsDir, dir)).forEach(file => {
let name = path.basename(file, ".svg") + suffix
values[name] = {name, fullPath: path.join(iconsDir, dir, file)}
})
})
matchComponents({
"hero": ({name, fullPath}) => {
let content = fs.readFileSync(fullPath).toString().replace(/\r?\n|\r/g, "")
let size = theme("spacing.6")
if (name.endsWith("-mini")) {
size = theme("spacing.5")
} else if (name.endsWith("-micro")) {
size = theme("spacing.4")
}
return {
[`--hero-${name}`]: `url('data:image/svg+xml;utf8,${content}')`,
"-webkit-mask": `var(--hero-${name})`,
"mask": `var(--hero-${name})`,
"mask-repeat": "no-repeat",
"background-color": "currentColor",
"vertical-align": "middle",
"display": "inline-block",
"width": size,
"height": size
}
}
}, {values})
})
]
}
}
44 changes: 21 additions & 23 deletions assets/vendor/topbar.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
/**
* @license MIT
* topbar 1.0.0, 2021-01-06
* Modifications:
* - add delayedShow(time) (2022-09-21)
* http://buunguyen.github.io/topbar
* topbar 2.0.0, 2023-02-04
* https://buunguyen.github.io/topbar
* Copyright (c) 2021 Buu Nguyen
*/
(function (window, document) {
Expand Down Expand Up @@ -98,26 +96,26 @@
for (var key in opts)
if (options.hasOwnProperty(key)) options[key] = opts[key];
},
delayedShow: function(time) {
show: function (delay) {
if (showing) return;
if (delayTimerId) return;
delayTimerId = setTimeout(() => topbar.show(), time);
},
show: function () {
if (showing) return;
showing = true;
if (fadeTimerId !== null) window.cancelAnimationFrame(fadeTimerId);
if (!canvas) createCanvas();
canvas.style.opacity = 1;
canvas.style.display = "block";
topbar.progress(0);
if (options.autoRun) {
(function loop() {
progressTimerId = window.requestAnimationFrame(loop);
topbar.progress(
"+" + 0.05 * Math.pow(1 - Math.sqrt(currentProgress), 2)
);
})();
if (delay) {
if (delayTimerId) return;
delayTimerId = setTimeout(() => topbar.show(), delay);
} else {
showing = true;
if (fadeTimerId !== null) window.cancelAnimationFrame(fadeTimerId);
if (!canvas) createCanvas();
canvas.style.opacity = 1;
canvas.style.display = "block";
topbar.progress(0);
if (options.autoRun) {
(function loop() {
progressTimerId = window.requestAnimationFrame(loop);
topbar.progress(
"+" + 0.05 * Math.pow(1 - Math.sqrt(currentProgress), 2)
);
})();
}
}
},
progress: function (to) {
Expand Down
Loading

0 comments on commit d7a0aa3

Please sign in to comment.