Created
May 22, 2020 22:31
-
-
Save kasrak/f1fb524f9364f8cfc594bca60dcc4248 to your computer and use it in GitHub Desktop.
Scouting block from https://www.youtube.com/watch?v=z6pRfEL-p4E
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const mapsToken = 'Your Google Maps API token'; | |
export const weatherToken = 'Your OpenWeatherMap API token'; | |
export const fromPhoneNumber = 'Your Twilio phone number'; | |
export const twilioSid = 'Your Twilio SID'; | |
export const twilioToken = 'Your Twilio token'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, {useState, useEffect} from 'react'; | |
import {cursor} from '@airtable/blocks'; | |
import { | |
initializeBlock, | |
useBase, | |
useRecordById, | |
useLoadable, | |
useWatchable, | |
Box, | |
Text, | |
Button, | |
} from '@airtable/blocks/ui'; | |
import { | |
mapsToken, | |
weatherToken, | |
fromPhoneNumber, | |
twilioSid, | |
twilioToken, | |
} from './config'; | |
function ScoutBlock() { | |
const [selectedRecordId, setSelectedRecordId] = useState(null); | |
useLoadable(cursor); | |
useWatchable(cursor, ['selectedRecordIds'], () => { | |
if (cursor.selectedRecordIds.length > 0) { | |
setSelectedRecordId(cursor.selectedRecordIds[0]); | |
} | |
}); | |
useWatchable(cursor, ['activeTableId', 'activeViewId'], () => { | |
setSelectedRecordId(null); | |
}); | |
const base = useBase(); | |
const table = base.getTable('Filming Locations'); | |
let content; | |
if (cursor.activeTableId !== table.id || !selectedRecordId) { | |
content = <Text>Select a record from the “{table.name}” table to see previews.</Text>; | |
} else { | |
content = <RecordPreview table={table} selectedRecordId={selectedRecordId} />; | |
} | |
return ( | |
<Box | |
position="absolute" | |
width="100vw" | |
height="100vh" | |
display="flex" | |
flexDirection="column" | |
alignItems="center" justifyContent="center"> | |
{content} | |
</Box> | |
); | |
} | |
function Weather({lat, lng}) { | |
const [forecast, setForecast] = useState(null); | |
useEffect(() => { | |
async function fetchForecast() { | |
const response = await fetch(`https://api.openweathermap.org/data/2.5/weather?units=imperial&lat=${lat}&lon=${lng}&appid=${weatherToken}`); | |
const json = await response.json(); | |
setForecast(json); | |
} | |
fetchForecast(); | |
}, [lat, lng]); | |
return forecast ? ( | |
<> | |
{Math.round(forecast.main.temp)}°F | |
<br /> | |
{forecast.weather[0].description} | |
</> | |
) : <>Loading weather...</>; | |
} | |
function SendSmsButton({message}) { | |
const base = useBase(); | |
const [sendingProgress, setSendingProgress] = useState(null); | |
async function sendSms() { | |
setSendingProgress(0); | |
const crew = await base.getTable('Crew').selectRecordsAsync(); | |
let progress = 0; | |
for (const crewMember of crew.records) { | |
const toPhoneNumber = crewMember.getCellValue('Phone Number'); | |
const formData = new FormData(); | |
formData.append('To', toPhoneNumber); | |
formData.append('From', fromPhoneNumber); | |
formData.append('Body', message); | |
await fetch( | |
`https://api.twilio.com/2010-04-01/Accounts/${twilioSid}/Messages.json`, | |
{ | |
method: 'POST', | |
body: formData, | |
headers: { | |
Authorization: 'Basic ' + btoa(`${twilioSid}:${twilioToken}`), | |
}, | |
}, | |
); | |
progress++; | |
setSendingProgress(progress / crew.records.length); | |
} | |
setSendingProgress(null); | |
} | |
return ( | |
<Button | |
variant="primary" | |
icon="phone" | |
disabled={sendingProgress !== null} | |
onClick={sendSms} | |
> | |
{sendingProgress ? `Sending SMS... (${Math.round(sendingProgress * 100)}%)` : 'Meet here!'} | |
</Button> | |
); | |
} | |
// Shows a preview, or a message about what the user should do to see a preview. | |
function RecordPreview({ | |
table, | |
selectedRecordId, | |
}) { | |
// Triggers a re-render if the record changes. Preview URL cell value | |
// might have changed, or record might have been deleted. | |
const selectedRecord = useRecordById(table, selectedRecordId ? selectedRecordId : '', { | |
fields: ['Address', 'Lat', 'Lng'], | |
}); | |
const address = selectedRecord.getCellValue('Address'); | |
const lat = selectedRecord.getCellValue('Lat'); | |
const lng = selectedRecord.getCellValue('Lng'); | |
if (!address) { | |
return <Text>The address field is empty</Text>; | |
} else { | |
const previewUrl = `https://google.com/maps/embed/v1/streetview?key=${mapsToken}&location=${lat},${lng}&fov=100`; | |
return ( | |
<> | |
<iframe | |
key={previewUrl} | |
style={{flex: 'auto', width: '100%'}} | |
src={previewUrl} | |
frameBorder="0" | |
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" | |
allowFullScreen | |
/> | |
<Box | |
display="flex" | |
alignItems="center" | |
justifyContent="space-between" | |
backgroundColor="#111" | |
paddingX={2} | |
paddingY={1} | |
textColor="white" | |
fontSize="large" | |
width="100%"> | |
<Weather lat={lat} lng={lng} /> | |
<SendSmsButton message={`Hello! Please meet at ${address}`} /> | |
</Box> | |
</> | |
); | |
} | |
} | |
initializeBlock(() => <ScoutBlock />); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment