├── .devcontainer ├── Dockerfile ├── devcontainer.json └── library-scripts │ ├── docker-in-docker.sh │ └── node-debian.sh ├── .github └── workflows │ ├── 2wr-app.yaml │ ├── admin.yaml │ └── api.yaml ├── .gitignore ├── .vscode ├── launch.json ├── settings.json └── tasks.json ├── 2wr-app ├── .env-sample ├── .gitignore ├── .prettierrc ├── README.md ├── babel.config.js ├── code-tour │ └── UITour.tour ├── jsconfig.json ├── package-lock.json ├── package.json ├── playwright.config.js ├── public │ ├── favicon.ico │ ├── images │ │ ├── hazards │ │ │ ├── earthquake-description.png │ │ │ ├── earthquake.png │ │ │ ├── flood.png │ │ │ ├── landslide.png │ │ │ ├── power-outage.png │ │ │ ├── public-health-emergency.png │ │ │ ├── radiological.png │ │ │ ├── severe-weather.png │ │ │ ├── tsunami.png │ │ │ ├── volcano.png │ │ │ └── wildfire.png │ │ └── kits │ │ │ ├── build-a-kit.png │ │ │ ├── child-kit.png │ │ │ ├── go-kit.png │ │ │ ├── home-kit.png │ │ │ ├── pet-kit.png │ │ │ ├── vehicle-kit.png │ │ │ └── work-kit.png │ ├── img │ │ └── icons │ │ │ ├── android-chrome-192x192.png │ │ │ ├── android-chrome-512x512.png │ │ │ ├── android-chrome-maskable-192x192.png │ │ │ ├── android-chrome-maskable-512x512.png │ │ │ ├── apple-touch-icon-120x120.png │ │ │ ├── apple-touch-icon-152x152.png │ │ │ ├── apple-touch-icon-180x180.png │ │ │ ├── apple-touch-icon-60x60.png │ │ │ ├── apple-touch-icon-76x76.png │ │ │ ├── apple-touch-icon.png │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── msapplication-icon-144x144.png │ │ │ ├── mstile-150x150.png │ │ │ └── safari-pinned-tab.svg │ ├── index.html │ ├── robots.txt │ └── service-worker.js ├── src │ ├── App.vue │ ├── api │ │ ├── base-api-instance.js │ │ ├── base-kit-api.js │ │ ├── emergency-kit-api.js │ │ ├── family-plans-api.js │ │ ├── hazard-hunt-api.js │ │ ├── hazard-info-api.js │ │ └── photos-api.js │ ├── assets │ │ ├── app.scss │ │ └── logo.svg │ ├── auth │ │ └── index.js │ ├── components │ │ ├── common │ │ │ ├── ConfirmDialog.vue │ │ │ ├── DatePickerInput.vue │ │ │ ├── EditableTextBlock.vue │ │ │ ├── IconTextBlock.vue │ │ │ ├── InfoBar.vue │ │ │ ├── SecureImg.vue │ │ │ └── globalComponents.js │ │ ├── prepare │ │ │ ├── emergency-kits │ │ │ │ ├── emergency-kit-build.vue │ │ │ │ ├── emergency-kit-details.vue │ │ │ │ └── emergency-kit-list.vue │ │ │ ├── family-plans │ │ │ │ ├── address-view.vue │ │ │ │ ├── children-list.vue │ │ │ │ ├── editors │ │ │ │ │ ├── address-editor.vue │ │ │ │ │ ├── child-editor.vue │ │ │ │ │ ├── emergency-contact-editor.vue │ │ │ │ │ ├── pet-editor.vue │ │ │ │ │ ├── photo-editor.vue │ │ │ │ │ ├── photos-editor.vue │ │ │ │ │ └── route-location-editor.vue │ │ │ │ ├── emergency-contact-view.vue │ │ │ │ ├── family-plan-contacts-view.vue │ │ │ │ ├── family-plans-list.vue │ │ │ │ ├── family-plans-view.vue │ │ │ │ ├── pets-list.vue │ │ │ │ └── route-location-list.vue │ │ │ ├── hazards │ │ │ │ ├── hazard-hunt-list.vue │ │ │ │ ├── hazard-hunt.vue │ │ │ │ ├── hazard-info-list.vue │ │ │ │ └── hazard-info.vue │ │ │ ├── make-a-plan │ │ │ │ └── make-a-plan.vue │ │ │ └── prepare-landing.vue │ │ ├── recent │ │ │ └── recent-landing.vue │ │ ├── settings │ │ │ └── settings-landing.vue │ │ └── welcome │ │ │ └── welcome-landing.vue │ ├── functions │ │ ├── goBack.js │ │ └── setFocusVuetify.js │ ├── lookups │ │ └── states.js │ ├── main.js │ ├── models │ │ └── family-plans │ │ │ ├── Address.js │ │ │ ├── Child.js │ │ │ ├── EmergencyContact.js │ │ │ ├── FamilyPlan.js │ │ │ ├── Pet.js │ │ │ └── RouteLocation.js │ ├── plugins │ │ └── vuetify.js │ ├── register-service-worker.js │ ├── router │ │ ├── familyPlanRoutes.js │ │ └── index.js │ ├── rules │ │ └── index.js │ ├── store │ │ ├── index.js │ │ └── modules │ │ │ ├── global │ │ │ └── global-store.js │ │ │ └── prepare │ │ │ ├── base-kits │ │ │ └── base-kit-store.js │ │ │ ├── emergency-kits │ │ │ └── emergency-kit-store.js │ │ │ ├── family-plans │ │ │ ├── actions.js │ │ │ ├── getters.js │ │ │ ├── index.js │ │ │ ├── mutations.js │ │ │ └── state.js │ │ │ └── hazards │ │ │ ├── hazard-hunt-store.js │ │ │ └── hazard-info-store.js │ └── views │ │ ├── prepare │ │ ├── emergency-kits │ │ │ ├── emergency-kit-build.vue │ │ │ ├── emergency-kit-details.vue │ │ │ └── emergency-kit-listing.vue │ │ ├── family-plans │ │ │ ├── children.vue │ │ │ ├── contacts.vue │ │ │ ├── distant-contacts.vue │ │ │ ├── landing.vue │ │ │ ├── pets.vue │ │ │ ├── routes.vue │ │ │ └── view.vue │ │ ├── hazards │ │ │ ├── hazard-hunt-list-view.vue │ │ │ ├── hazard-hunt-view.vue │ │ │ ├── hazard-info-list-view.vue │ │ │ └── hazard-info-view.vue │ │ ├── make-a-plan │ │ │ └── make-a-plan.vue │ │ └── prepare.vue │ │ ├── recent │ │ └── recent.vue │ │ ├── settings │ │ └── settings.vue │ │ └── welcome │ │ └── welcome.vue ├── tests │ ├── global-setup.js │ ├── hazard-info.spec.js │ └── welcome.spec.js └── vue.config.js ├── LICENSE ├── README.md ├── TwoWeeksReady.Common ├── EmergencyKits │ ├── BaseKit.cs │ ├── BaseKitItem.cs │ ├── Kit.cs │ └── KitItem.cs ├── FamilyMembers │ └── FamilyMember.cs ├── FamilyPlans │ ├── Address.cs │ ├── Child.cs │ ├── Contact.cs │ ├── FamilyPlan.cs │ ├── Pet.cs │ ├── RouteLocation.cs │ └── WalkThroughStep.cs ├── Hazards │ ├── HazardBaseInfo.cs │ ├── HazardHunt.cs │ └── HazardInfo.cs └── TwoWeeksReady.Common.csproj ├── admin ├── TwoWeeksReady.Admin │ ├── App.razor │ ├── Components │ │ └── KitItemDisplay.razor │ ├── Data │ │ ├── ClientImage.cs │ │ ├── ClientImageService.cs │ │ ├── FunctionsRepository.cs │ │ ├── IRepository.cs │ │ └── StubRepository.cs │ ├── Pages │ │ ├── Error.cshtml │ │ ├── Error.cshtml.cs │ │ ├── HazardHunts │ │ │ ├── Details.razor │ │ │ └── List.razor │ │ ├── HazardInfos │ │ │ ├── Details.razor │ │ │ └── List.razor │ │ ├── Index.razor │ │ ├── Kits │ │ │ ├── Details.razor │ │ │ └── List.razor │ │ ├── Login.cshtml │ │ ├── Login.cshtml.cs │ │ ├── Logout.cshtml │ │ ├── Logout.cshtml.cs │ │ └── _Host.cshtml │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Security │ │ └── TokenProvider.cs │ ├── Shared │ │ ├── AccessControl.razor │ │ ├── MainLayout.razor │ │ ├── MainLayout.razor.css │ │ ├── NavMenu.razor │ │ └── NavMenu.razor.css │ ├── Startup.cs │ ├── TwoWeeksReady.Admin.csproj │ ├── _Imports.razor │ ├── appsettings.Development.json │ ├── appsettings.json │ └── wwwroot │ │ ├── css │ │ ├── bootstrap │ │ │ ├── bootstrap.min.css │ │ │ └── bootstrap.min.css.map │ │ ├── open-iconic │ │ │ ├── FONT-LICENSE │ │ │ ├── ICON-LICENSE │ │ │ ├── README.md │ │ │ └── font │ │ │ │ ├── css │ │ │ │ └── open-iconic-bootstrap.min.css │ │ │ │ └── fonts │ │ │ │ ├── open-iconic.eot │ │ │ │ ├── open-iconic.otf │ │ │ │ ├── open-iconic.svg │ │ │ │ ├── open-iconic.ttf │ │ │ │ └── open-iconic.woff │ │ └── site.css │ │ └── favicon.ico └── admin.sln ├── api ├── .gitignore ├── .vscode │ ├── extensions.json │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── CodeTour │ └── ApiTour.tour ├── README.md ├── TwoWeeksReady │ ├── .vscode │ │ ├── extensions.json │ │ ├── launch.json │ │ ├── settings.json │ │ └── tasks.json │ ├── Authorization │ │ ├── AuthorizationExtensions.cs │ │ └── Roles.cs │ ├── Common │ │ └── BaseFunction.cs │ ├── EmergencyKits │ │ ├── BaseKitsApi.cs │ │ ├── CreateKitFromBaseRequest.cs │ │ └── EmergencyKitsApi.cs │ ├── FamilyMembers │ │ └── FamilyMembersApi.cs │ ├── FamilyPlans │ │ └── FamilyPlansApi.cs │ ├── Hazards │ │ ├── HazardApiBase.cs │ │ ├── HazardHuntApi.cs │ │ └── HazardInfoApi.cs │ ├── Photos │ │ └── PhotoFunction.cs │ ├── Startup.cs │ ├── TwoWeeksReady.csproj │ └── host.json ├── api.code-workspace └── api.sln ├── assets ├── icons │ ├── app │ │ ├── 2 Weeks Ready Icon-128.png │ │ ├── 2 Weeks Ready Icon-16.png │ │ ├── 2 Weeks Ready Icon-256.png │ │ ├── 2 Weeks Ready Icon-32.png │ │ ├── 2 Weeks Ready Icon-512.png │ │ ├── 2 Weeks Ready Icon-64.png │ │ └── 2 Weeks Ready Icon.svg │ └── kits │ │ ├── 2WR Kit.png │ │ ├── 2WR Kit.svg │ │ ├── Child Kit.svg │ │ ├── Child Kit128-.png │ │ ├── Child Kit16-.png │ │ ├── Child Kit256-.png │ │ ├── Child Kit32-.png │ │ ├── Child Kit512-.png │ │ ├── Child Kit64-.png │ │ ├── Miscellaneous Icons V3.ai │ │ ├── Pet Kit.svg │ │ ├── Pet Kit128-.png │ │ ├── Pet Kit16-.png │ │ ├── Pet Kit256-.png │ │ ├── Pet Kit32-.png │ │ ├── Pet Kit512-.png │ │ ├── Pet Kit64-.png │ │ ├── Vehicle Kit.svg │ │ ├── Vehicle Kit128-.png │ │ ├── Vehicle Kit16-.png │ │ ├── Vehicle Kit256-.png │ │ ├── Vehicle Kit32-.png │ │ ├── Vehicle Kit512-.png │ │ └── Vehicle Kit64-.png ├── images │ ├── 210909_2WR_EMAIL GRAPHIC.png │ ├── Build A Kit │ │ ├── Child Kit.png │ │ ├── Home Kit.png │ │ ├── Pet Kit.png │ │ ├── Vehicle Kit.png │ │ └── Work Kit.png │ ├── Hazard Information │ │ ├── Earthquake.png │ │ ├── Flood.png │ │ ├── Landslide.png │ │ ├── Power Outage.png │ │ ├── Public Health Emergency.png │ │ ├── Radiological.png │ │ ├── Severe Weather.png │ │ ├── Tsunami.png │ │ ├── Volcano.png │ │ └── Wildfire.png │ ├── codetour_api.png │ ├── codetour_ui.png │ ├── forestfire_resized.jpg │ ├── seismograph_resized.jpg │ └── twoweeksready.png ├── models │ ├── EmergencyKits.drawio │ ├── EmergencyKits.png │ ├── HazardHuntHazardInformation.drawio │ └── HazardHuntHazardInformation.png └── wiki │ ├── Family plan page 1.PNG │ ├── Family plan page 2.PNG │ ├── Family plan page 3.PNG │ ├── Family plan page 4.PNG │ ├── Family plan page 5.PNG │ ├── Family plan page 6.PNG │ ├── Family plan page 7.PNG │ ├── Family plan page 8.PNG │ ├── HazardHuntDetails.png │ ├── HazardHuntEntry.png │ └── HazardHuntListing.png ├── az ├── create-admin-app-resources.sh ├── create-backend-resources.sh ├── create-frontend-resources.sh ├── deploy-admin-app.sh ├── deploy-backend.sh └── deploy-frontend.sh ├── solution architecture.xml └── tools ├── CosmosEmulator ├── CosmosEmulator.csproj ├── CosmosInitializer.cs ├── Program.cs ├── start-emulator.sh └── stop-emulator.sh ├── first-build.sh ├── samples └── local.settings.sample.json └── setup-config.sh /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # Find the Dockerfile for mcr.microsoft.com/azure-functions/dotnet:3.0-dotnet3-core-tools at this URL 2 | # https://github.com/Azure/azure-functions-docker/blob/main/host/3.0/buster/amd64/dotnet/dotnet-core-tools.Dockerfile 3 | FROM mcr.microsoft.com/azure-functions/dotnet:4-dotnet6-core-tools 4 | 5 | # Uncomment following lines If you want to enable Development Container Script 6 | # For more details https://github.com/microsoft/vscode-dev-containers/tree/main/script-library 7 | 8 | # Avoid warnings by switching to noninteractive 9 | # ENV DEBIAN_FRONTEND=noninteractive 10 | 11 | # # Comment out these lines if you want to use zsh. 12 | 13 | ARG INSTALL_ZSH=false 14 | ARG USERNAME=vscode 15 | ARG USER_UID=1000 16 | ARG USER_GID=$USER_UID 17 | 18 | RUN apt-get update && curl -ssL https://raw.githubusercontent.com/microsoft/vscode-dev-containers/main/script-library/common-debian.sh -o /tmp/common-script.sh \ 19 | && /bin/bash /tmp/common-script.sh "$INSTALL_ZSH" "$USERNAME" "$USER_UID" "$USER_GID" \ 20 | && rm /tmp/common-script.sh 21 | 22 | # Setup .NET 5 & 6 SDKs 23 | RUN wget https://packages.microsoft.com/config/debian/10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb 24 | RUN dpkg -i packages-microsoft-prod.deb 25 | RUN rm packages-microsoft-prod.deb 26 | RUN apt-get update \ 27 | && apt-get install -y apt-transport-https \ 28 | && apt-get update \ 29 | && apt-get install -y dotnet-sdk-5.0 \ 30 | && apt-get install -y dotnet-sdk-6.0 31 | 32 | # Install Chrome for Desktop Testing through VNC 33 | RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ 34 | && curl -sSL https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -o /tmp/chrome.deb \ 35 | && apt-get -y install /tmp/chrome.deb -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: 2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.209.6/containers/azure-functions-dotnetcore-3.1 3 | { 4 | "name": "TwoWeeksReady", 5 | "dockerFile": "Dockerfile", 6 | "forwardPorts": [ 7071, 6080, 5901 ], 7 | 8 | // Set *default* container specific settings.json values on container create. 9 | "settings": {}, 10 | 11 | // Add the IDs of extensions you want installed when the container is created. 12 | "extensions": [ 13 | "ms-azuretools.vscode-azurefunctions", 14 | "ms-dotnettools.csharp", 15 | "azurite.azurite", 16 | //"ms-azuretools.vscode-cosmosdb" 17 | // unable to get preview extension working through devcontainer emulator due to certificate error, but works with deprecated feature in Azure Storage Explorer 18 | ], 19 | 20 | "features": { 21 | "docker-in-docker": { 22 | "version": "latest", 23 | "moby": true 24 | }, 25 | "node": { 26 | "version": "lts", 27 | "nodeGypDependencies": true 28 | }, 29 | "desktop-lite": { 30 | "password": "vscode", 31 | "webPort": "6080", 32 | "vncPort": "5901" 33 | }, 34 | "github-cli": "latest" 35 | }, 36 | 37 | // Use 'postCreateCommand' to run commands after the container is created. 38 | "postCreateCommand": "bash -i tools/first-build.sh", 39 | 40 | // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. 41 | "remoteUser": "vscode" 42 | } 43 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | // Use IntelliSense to find out which attributes exist for C# debugging 6 | // Use hover for the description of the existing attributes 7 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md 8 | "name": ".NET Core Launch (web)", 9 | "type": "coreclr", 10 | "request": "launch", 11 | "preLaunchTask": "build", 12 | // If you have changed target frameworks, make sure to update the program path. 13 | "program": "${workspaceFolder}/admin/TwoWeeksReady.Admin/bin/Debug/net5.0/TwoWeeksReady.Admin.dll", 14 | "args": [], 15 | "cwd": "${workspaceFolder}/admin/TwoWeeksReady.Admin", 16 | "stopAtEntry": false, 17 | // Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser 18 | "serverReadyAction": { 19 | "action": "openExternally", 20 | "pattern": "\\bNow listening on:\\s+(https?://\\S+)" 21 | }, 22 | "env": { 23 | "ASPNETCORE_ENVIRONMENT": "Development" 24 | }, 25 | "sourceFileMap": { 26 | "/Views": "${workspaceFolder}/Views" 27 | } 28 | }, 29 | { 30 | "name": ".NET Core Attach", 31 | "type": "coreclr", 32 | "request": "attach", 33 | "processId": "${command:pickProcess}" 34 | } 35 | ] 36 | } -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "azureFunctions.projectSubpath": "api/TwoWeeksReady", 3 | "azureFunctions.deploySubpath": "api/TwoWeeksReady/bin/Release/net6.0/publish", 4 | "azureFunctions.projectLanguage": "C#", 5 | "azureFunctions.projectRuntime": "~4", 6 | "debug.internalConsoleOptions": "neverOpen", 7 | "azureFunctions.preDeployTask": "publish (functions)" 8 | } -------------------------------------------------------------------------------- /2wr-app/.env-sample: -------------------------------------------------------------------------------- 1 | NODE_ENV=development 2 | VUE_APP_VERSION_TAG=LOCALDEV 3 | VUE_APP_TITLE=Two Weeks Ready - Local 4 | VUE_APP_APIROOT=http://localhost:7071/api/ 5 | VUE_APP_AUTH0_DOMAIN=login.2wr.org 6 | VUE_APP_AUTH0_CLIENTID=6TSzRpgtMKR3NI1D4Is1nGO6brBB2wB0 7 | VUE_APP_AUTH0_AUDIENCE=https://2wrdev.azurewebsites.net -------------------------------------------------------------------------------- /2wr-app/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | /tests/_storagestate 6 | /playwright-report 7 | 8 | # local env files 9 | .env 10 | .env.local 11 | .env.*.local 12 | 13 | #test results 14 | /test-results 15 | 16 | # Log files 17 | npm-debug.log* 18 | yarn-debug.log* 19 | yarn-error.log* 20 | pnpm-debug.log* 21 | 22 | # Editor directories and files 23 | .idea 24 | .vscode 25 | *.suo 26 | *.ntvs* 27 | *.njsproj 28 | *.sln 29 | *.sw? 30 | -------------------------------------------------------------------------------- /2wr-app/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 2, 3 | "useTabs": false, 4 | 5 | } 6 | -------------------------------------------------------------------------------- /2wr-app/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /2wr-app/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "baseUrl": ".", 6 | "paths": { 7 | "@/*": ["./src/*"] 8 | }, 9 | "types": ["vuetify"] 10 | }, 11 | "exclude": ["node_modules", "dist"], 12 | "include": ["src/**/*"] 13 | } -------------------------------------------------------------------------------- /2wr-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "2wr-app", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "cross-env NODE_ENV=development npm-run-all --parallel dev:*", 7 | "dev:serve": "vue-cli-service serve", 8 | "dev:napi": "func start --prefix ..\\api\\TwoWeeksReady\\", 9 | "serve": "vue-cli-service serve", 10 | "build": "vue-cli-service build", 11 | "lint": "vue-cli-service lint", 12 | "api": "func start --prefix ..\\api\\TwoWeeksReady\\", 13 | "azurite": "azurite --silent --location c:\\temp\\azurite", 14 | "e2etest": "playwright test" 15 | }, 16 | "dependencies": { 17 | "@auth0/auth0-spa-js": "^1.13.6", 18 | "@vue/composition-api": "^1.0.0-rc.7", 19 | "auth0-js": "^9.14.2", 20 | "core-js": "^3.8.2", 21 | "localforage": "^1.9.0", 22 | "lodash": "^4.17.21", 23 | "redaxios": "^0.3.0", 24 | "register-service-worker": "^1.7.2", 25 | "us": "^2.0.0", 26 | "uuid": "^3.4.0", 27 | "vue": "^2.6.11", 28 | "vue-router": "^3.4.9", 29 | "vuetify": "^2.5.10", 30 | "vuex": "^3.6.0" 31 | }, 32 | "devDependencies": { 33 | "@mdi/font": "^5.8.55", 34 | "@playwright/test": "^1.40.0", 35 | "@vue/cli-plugin-babel": "^4.5.10", 36 | "@vue/cli-plugin-eslint": "^4.5.10", 37 | "@vue/cli-plugin-pwa": "^4.5.10", 38 | "@vue/cli-plugin-router": "^4.5.10", 39 | "@vue/cli-service": "^4.5.10", 40 | "axe-playwright": "^1.2.3", 41 | "babel-eslint": "^10.1.0", 42 | "cross-env": "^7.0.3", 43 | "dotenv-webpack": "^4.0.0", 44 | "eslint": "^6.7.2", 45 | "eslint-plugin-vue": "^6.2.2", 46 | "npm-run-all": "^4.1.5", 47 | "sass": "~1.32.4", 48 | "sass-loader": "^8.0.2", 49 | "vue-cli-plugin-vuetify": "^2.0.9", 50 | "vue-template-compiler": "^2.6.11", 51 | "vuetify-loader": "^1.3.0" 52 | }, 53 | "eslintConfig": { 54 | "root": true, 55 | "env": { 56 | "node": true 57 | }, 58 | "extends": [ 59 | "plugin:vue/essential", 60 | "eslint:recommended" 61 | ], 62 | "parserOptions": { 63 | "parser": "babel-eslint" 64 | }, 65 | "rules": {} 66 | }, 67 | "browserslist": [ 68 | "> 1%", 69 | "last 2 versions", 70 | "not dead" 71 | ] 72 | } 73 | -------------------------------------------------------------------------------- /2wr-app/playwright.config.js: -------------------------------------------------------------------------------- 1 | // playwright.config.js 2 | // @ts-check 3 | /** @type {import('@playwright/test').PlaywrightTestConfig} */ 4 | 5 | if ( 6 | !process.env.TWO_WEEKS_READY_E2E_TEST_USERNAME || 7 | !process.env.TWO_WEEKS_READY_E2E_TEST_PASSWORD 8 | ) { 9 | console.error( 10 | "TWO_WEEKS_READY_E2E_TEST_USERNAME and TWO_WEEKS_READY_E2E_TEST_PASSWORD environment variables must be set for end-to-end tests to run." 11 | ); 12 | process.exit(-1); 13 | } 14 | 15 | const config = { 16 | timeout: 30000, 17 | webServer: { 18 | command: "npm run serve", 19 | url: "http://localhost:8080", 20 | timeout: 120 * 1000, 21 | reuseExistingServer: !process.env.CI 22 | }, 23 | globalSetup: require.resolve("./tests/global-setup"), 24 | use: { 25 | baseURL: "http://localhost:8080/", 26 | screenshot: "only-on-failure", 27 | recording: "retain-on-failure", 28 | trace: "retain-on-failure", 29 | // Tell all tests to load signed-in state from 'storageState.json'. 30 | storageState: "./tests/_storagestate/storageState.json" 31 | }, 32 | reporter: [["list"], ["html", { output: "reports/report.html" }]] 33 | }; 34 | module.exports = config; 35 | -------------------------------------------------------------------------------- /2wr-app/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/favicon.ico -------------------------------------------------------------------------------- /2wr-app/public/images/hazards/earthquake-description.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/earthquake-description.png -------------------------------------------------------------------------------- /2wr-app/public/images/hazards/earthquake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/earthquake.png -------------------------------------------------------------------------------- /2wr-app/public/images/hazards/flood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/flood.png -------------------------------------------------------------------------------- /2wr-app/public/images/hazards/landslide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/landslide.png -------------------------------------------------------------------------------- /2wr-app/public/images/hazards/power-outage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/power-outage.png -------------------------------------------------------------------------------- /2wr-app/public/images/hazards/public-health-emergency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/public-health-emergency.png -------------------------------------------------------------------------------- /2wr-app/public/images/hazards/radiological.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/radiological.png -------------------------------------------------------------------------------- /2wr-app/public/images/hazards/severe-weather.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/severe-weather.png -------------------------------------------------------------------------------- /2wr-app/public/images/hazards/tsunami.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/tsunami.png -------------------------------------------------------------------------------- /2wr-app/public/images/hazards/volcano.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/volcano.png -------------------------------------------------------------------------------- /2wr-app/public/images/hazards/wildfire.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/wildfire.png -------------------------------------------------------------------------------- /2wr-app/public/images/kits/build-a-kit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/kits/build-a-kit.png -------------------------------------------------------------------------------- /2wr-app/public/images/kits/child-kit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/kits/child-kit.png -------------------------------------------------------------------------------- /2wr-app/public/images/kits/go-kit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/kits/go-kit.png -------------------------------------------------------------------------------- /2wr-app/public/images/kits/home-kit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/kits/home-kit.png -------------------------------------------------------------------------------- /2wr-app/public/images/kits/pet-kit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/kits/pet-kit.png -------------------------------------------------------------------------------- /2wr-app/public/images/kits/vehicle-kit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/kits/vehicle-kit.png -------------------------------------------------------------------------------- /2wr-app/public/images/kits/work-kit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/kits/work-kit.png -------------------------------------------------------------------------------- /2wr-app/public/img/icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /2wr-app/public/img/icons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/android-chrome-512x512.png -------------------------------------------------------------------------------- /2wr-app/public/img/icons/android-chrome-maskable-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/android-chrome-maskable-192x192.png -------------------------------------------------------------------------------- /2wr-app/public/img/icons/android-chrome-maskable-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/android-chrome-maskable-512x512.png -------------------------------------------------------------------------------- /2wr-app/public/img/icons/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /2wr-app/public/img/icons/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /2wr-app/public/img/icons/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /2wr-app/public/img/icons/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /2wr-app/public/img/icons/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /2wr-app/public/img/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /2wr-app/public/img/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/favicon-16x16.png -------------------------------------------------------------------------------- /2wr-app/public/img/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/favicon-32x32.png -------------------------------------------------------------------------------- /2wr-app/public/img/icons/msapplication-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/msapplication-icon-144x144.png -------------------------------------------------------------------------------- /2wr-app/public/img/icons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/mstile-150x150.png -------------------------------------------------------------------------------- /2wr-app/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= process.env.VUE_APP_TITLE %> 9 | 10 | 11 | 12 | 15 |
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /2wr-app/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /2wr-app/public/service-worker.js: -------------------------------------------------------------------------------- 1 | // custom service-worker.js 2 | if (workbox) { 3 | // adjust log level for displaying workbox logs 4 | //workbox.core.setLogLevel(workbox.core.LOG_LEVELS.debug) 5 | 6 | // apply precaching. In the built version, the precacheManifest will 7 | // be imported using importScripts (as is workbox itself) and we can 8 | // precache this. This is all we need for precaching 9 | workbox.precaching.precacheAndRoute(self.__precacheManifest); 10 | 11 | // Make sure to return a specific response for all navigation requests. 12 | // Since we have a SPA here, this should be index.html always. 13 | // https://stackoverflow.com/questions/49963982/vue-router-history-mode-with-pwa-in-offline-mode 14 | workbox.routing.registerNavigationRoute('/index.html') 15 | 16 | // Setup cache strategy for Google Fonts. They consist of two parts, a static one 17 | // coming from fonts.gstatic.com (strategy CacheFirst) and a more ferquently updated on 18 | // from fonts.googleapis.com. Hence, split in two registerroutes 19 | workbox.routing.registerRoute( 20 | /^https:\/\/fonts\.googleapis\.com/, 21 | new workbox.strategies.StaleWhileRevalidate({ 22 | cacheName: 'google-fonts-stylesheets', 23 | }) 24 | ); 25 | 26 | workbox.routing.registerRoute( 27 | /^https:\/\/fonts\.gstatic\.com/, 28 | new workbox.strategies.CacheFirst({ 29 | cacheName: 'google-fonts-webfonts', 30 | plugins: [ 31 | new workbox.cacheableResponse.Plugin({ 32 | statuses: [0, 200], 33 | }), 34 | new workbox.expiration.Plugin({ 35 | maxAgeSeconds: 60 * 60 * 24 * 365, 36 | maxEntries: 30, 37 | }), 38 | ], 39 | }) 40 | ); 41 | } 42 | 43 | //attempted api call regex: /^http[s]?(.*)\/api\/(.*)/ 44 | 45 | 46 | // This code listens for the user's confirmation to update the app. 47 | // self.addEventListener('message', (e) => { 48 | // if (!e.data) { 49 | // return; 50 | // } 51 | 52 | // switch (e.data) { 53 | // case 'skipWaiting': 54 | // self.skipWaiting(); 55 | // break; 56 | // default: 57 | // // NOOP 58 | // break; 59 | // } 60 | // }) 61 | 62 | // Listen to Push 63 | // self.addEventListener('push', (e) => { 64 | // let data 65 | // if (e.data) { 66 | // data = e.data.json() 67 | // } 68 | 69 | // const options = { 70 | // body: data.body, 71 | // icon: '/img/icons/android-chrome-192x192.png', 72 | // image: '/img/autumn-forest.png', 73 | // vibrate: [300, 200, 300], 74 | // badge: '/img/icons/plint-badge-96x96.png', 75 | // } 76 | 77 | // e.waitUntil(self.registration.showNotification(data.title, options)) 78 | // }) -------------------------------------------------------------------------------- /2wr-app/src/api/base-api-instance.js: -------------------------------------------------------------------------------- 1 | // Using RedAxios so we can intercept fetch if necessary 2 | import axios from "redaxios"; 3 | import { getAuthInstance } from "../auth"; 4 | const baseApiInstance = { 5 | async getInstance(customOptions) { 6 | // Allows options to be added by specific APIs 7 | const options = { ...customOptions }; 8 | options.baseURL = process.env.VUE_APP_APIROOT; 9 | const token = await getAuthInstance().getTokenSilently(); 10 | 11 | // Allows headers to be set by client 12 | if (options.headers) { 13 | options.headers.Authorization = `Bearer ${token}`; 14 | } else { 15 | options.headers = { 16 | Authorization: `Bearer ${token}` 17 | }; 18 | } 19 | return axios.create(options); 20 | } 21 | }; 22 | 23 | export default baseApiInstance; 24 | -------------------------------------------------------------------------------- /2wr-app/src/api/base-kit-api.js: -------------------------------------------------------------------------------- 1 | import baseApiInstance from './base-api-instance'; 2 | 3 | const emergencyKitApi = { 4 | async getAll() { 5 | return (await baseApiInstance.getInstance()).get('basekits'); 6 | } 7 | } 8 | 9 | export default emergencyKitApi; -------------------------------------------------------------------------------- /2wr-app/src/api/emergency-kit-api.js: -------------------------------------------------------------------------------- 1 | import baseApiInstance from './base-api-instance'; 2 | 3 | const emergencyKitApi = { 4 | async getAllByBaseKitId(baseKitId) { 5 | return (await baseApiInstance.getInstance()).get(`emergencykits/${baseKitId}`); 6 | }, 7 | async getById(id) { 8 | return (await baseApiInstance.getInstance()).get(`emergencykit-by-id/${id}`); 9 | }, 10 | async create(newKit) { 11 | return (await baseApiInstance.getInstance()).post('emergencykit-create', newKit); 12 | }, 13 | async save(updatedKit) { 14 | return (await baseApiInstance.getInstance()).put('emergencykit-update', updatedKit); 15 | } 16 | } 17 | 18 | export default emergencyKitApi; -------------------------------------------------------------------------------- /2wr-app/src/api/family-plans-api.js: -------------------------------------------------------------------------------- 1 | import baseApiInstance from './base-api-instance'; 2 | 3 | export default { 4 | async getAll() { 5 | return (await baseApiInstance.getInstance()).get("familyplans-getall"); 6 | }, 7 | async upsertPlan(plan) { 8 | return (await baseApiInstance.getInstance()).post('familyplans-upsert', plan); 9 | }, 10 | async deletePlan(plan) { 11 | return (await baseApiInstance.getInstance()).delete(`familyplans-delete/${plan.id}`); 12 | } 13 | } -------------------------------------------------------------------------------- /2wr-app/src/api/hazard-hunt-api.js: -------------------------------------------------------------------------------- 1 | import baseApiInstance from './base-api-instance'; 2 | 3 | export default { 4 | async getDocuments() { 5 | return (await baseApiInstance.getInstance()).get('hazardhunt-list'); 6 | }, 7 | async get(id) { 8 | return (await baseApiInstance.getInstance()).get(`hazardhunt-by-id/${id}`); 9 | } 10 | }; -------------------------------------------------------------------------------- /2wr-app/src/api/hazard-info-api.js: -------------------------------------------------------------------------------- 1 | import baseApiInstance from './base-api-instance'; 2 | 3 | export default { 4 | async getAll() { 5 | return (await baseApiInstance.getInstance()).get('hazardinfo-list'); 6 | }, 7 | 8 | async get(id) { 9 | return (await baseApiInstance.getInstance()).get(`hazardinfo-by-id/${id}`); 10 | } 11 | }; -------------------------------------------------------------------------------- /2wr-app/src/api/photos-api.js: -------------------------------------------------------------------------------- 1 | import baseApiInstance from "./base-api-instance"; 2 | import { getAuthInstance } from "../auth"; 3 | 4 | export default { 5 | async uploadPhoto(photo) { 6 | 7 | const token = await getAuthInstance().getTokenSilently(); 8 | 9 | // Can't use redaxios (bug dealing with blobs, so use fetch) 10 | return fetch(`${process.env.VUE_APP_APIROOT}photo`,{ 11 | method: "POST", 12 | body: photo, 13 | headers: { 14 | "Authorization": `Bearer ${token}`, 15 | "Content-Type": photo.type 16 | } 17 | }); 18 | }, 19 | 20 | async getPhoto(photo) { 21 | return (await baseApiInstance.getInstance({ responseType: "blob", headers: { Accept: "image/*"}})).get(`photo/${photo}`); 22 | } 23 | }; 24 | -------------------------------------------------------------------------------- /2wr-app/src/assets/app.scss: -------------------------------------------------------------------------------- 1 | .pseudo-text-block-label { 2 | margin-left: .5rem; 3 | position: absolute; 4 | background-color: #fff; 5 | margin-top: -9px; 6 | padding: 1px; 7 | } 8 | 9 | .hidden { 10 | display: none; 11 | } 12 | .img-cover { 13 | object-fit: cover; 14 | } 15 | 16 | .cursor-pointer { 17 | cursor: pointer; 18 | } -------------------------------------------------------------------------------- /2wr-app/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | Artboard 46 2 | -------------------------------------------------------------------------------- /2wr-app/src/components/common/ConfirmDialog.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | -------------------------------------------------------------------------------- /2wr-app/src/components/common/DatePickerInput.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 74 | -------------------------------------------------------------------------------- /2wr-app/src/components/common/EditableTextBlock.vue: -------------------------------------------------------------------------------- 1 | 31 | 32 | 91 | 92 | -------------------------------------------------------------------------------- /2wr-app/src/components/common/IconTextBlock.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 21 | -------------------------------------------------------------------------------- /2wr-app/src/components/common/InfoBar.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 25 | -------------------------------------------------------------------------------- /2wr-app/src/components/common/SecureImg.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 30 | -------------------------------------------------------------------------------- /2wr-app/src/components/common/globalComponents.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import EditableTextBlock from './EditableTextBlock.vue'; 3 | import IconTextBlock from './IconTextBlock.vue'; 4 | import InfoBar from './InfoBar.vue'; 5 | import DatePickerInput from "./DatePickerInput.vue"; 6 | import SecureImg from './SecureImg.vue'; 7 | import ConfirmDialog from './ConfirmDialog.vue'; 8 | 9 | export default function () { 10 | Vue.component("EditableTextBlock", EditableTextBlock); 11 | Vue.component("IconTextBlock", IconTextBlock); 12 | Vue.component("InfoBar", InfoBar); 13 | Vue.component("DatePickerInput", DatePickerInput); 14 | Vue.component("SecureImg", SecureImg); 15 | Vue.component("ConfirmDialog", ConfirmDialog); 16 | } -------------------------------------------------------------------------------- /2wr-app/src/components/prepare/emergency-kits/emergency-kit-build.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | -------------------------------------------------------------------------------- /2wr-app/src/components/prepare/family-plans/address-view.vue: -------------------------------------------------------------------------------- 1 | 39 | 40 | 95 | -------------------------------------------------------------------------------- /2wr-app/src/components/prepare/family-plans/editors/address-editor.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 87 | -------------------------------------------------------------------------------- /2wr-app/src/components/prepare/family-plans/editors/emergency-contact-editor.vue: -------------------------------------------------------------------------------- 1 | 67 | 68 | 104 | -------------------------------------------------------------------------------- /2wr-app/src/components/prepare/family-plans/editors/pet-editor.vue: -------------------------------------------------------------------------------- 1 | 40 | 41 | 97 | -------------------------------------------------------------------------------- /2wr-app/src/components/prepare/family-plans/editors/photo-editor.vue: -------------------------------------------------------------------------------- 1 | 30 | 31 | 58 | 59 | -------------------------------------------------------------------------------- /2wr-app/src/components/prepare/family-plans/editors/photos-editor.vue: -------------------------------------------------------------------------------- 1 | 36 | 37 | 69 | 70 | -------------------------------------------------------------------------------- /2wr-app/src/components/prepare/family-plans/editors/route-location-editor.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 65 | -------------------------------------------------------------------------------- /2wr-app/src/components/prepare/family-plans/family-plans-list.vue: -------------------------------------------------------------------------------- 1 | 65 | 66 | 96 | -------------------------------------------------------------------------------- /2wr-app/src/components/prepare/hazards/hazard-hunt-list.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 62 | 63 | -------------------------------------------------------------------------------- /2wr-app/src/components/prepare/hazards/hazard-info-list.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 62 | 63 | -------------------------------------------------------------------------------- /2wr-app/src/components/prepare/make-a-plan/make-a-plan.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 26 | 27 | -------------------------------------------------------------------------------- /2wr-app/src/components/prepare/prepare-landing.vue: -------------------------------------------------------------------------------- 1 | 81 | 82 | 96 | -------------------------------------------------------------------------------- /2wr-app/src/components/recent/recent-landing.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 17 | -------------------------------------------------------------------------------- /2wr-app/src/components/settings/settings-landing.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 17 | -------------------------------------------------------------------------------- /2wr-app/src/components/welcome/welcome-landing.vue: -------------------------------------------------------------------------------- 1 | 60 | 61 | 79 | 84 | -------------------------------------------------------------------------------- /2wr-app/src/functions/goBack.js: -------------------------------------------------------------------------------- 1 | import router from "@/router"; 2 | 3 | export default function () { 4 | window.history.length > 1 ? router.go(-1) : router.push("/"); 5 | } -------------------------------------------------------------------------------- /2wr-app/src/functions/setFocusVuetify.js: -------------------------------------------------------------------------------- 1 | import { 2 | nextTick 3 | } from "@vue/composition-api"; 4 | 5 | export default function setFocusVuetify(refs, name) { 6 | nextTick(() => { 7 | var inputs = refs[name].$el.getElementsByTagName("input"); 8 | if (inputs && inputs.length > 0) inputs[0].focus(); 9 | }); 10 | } -------------------------------------------------------------------------------- /2wr-app/src/lookups/states.js: -------------------------------------------------------------------------------- 1 | import { states } from "us"; 2 | 3 | const stateList = [] 4 | 5 | for (const id in states) stateList.push({ text: states[id].name, value: states[id].abbr}); 6 | 7 | export default stateList; -------------------------------------------------------------------------------- /2wr-app/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import App from './App.vue'; 3 | import './register-service-worker'; 4 | import vuetify from './plugins/vuetify'; 5 | import router from './router'; 6 | import store from './store'; 7 | import { Auth0Plugin } from "./auth"; 8 | import VueCompositionAPI from '@vue/composition-api'; 9 | import globalComponents from "@/components/common/globalComponents"; 10 | import './assets/app.scss'; 11 | 12 | Vue.config.productionTip = false 13 | 14 | Vue.use(Auth0Plugin, { 15 | domain: process.env.VUE_APP_AUTH0_DOMAIN, 16 | clientId: process.env.VUE_APP_AUTH0_CLIENTID, 17 | audience: process.env.VUE_APP_AUTH0_AUDIENCE, 18 | onRedirectCallback: appState => { 19 | router.push( 20 | appState && appState.targetUrl 21 | ? appState.targetUrl 22 | : window.location.pathname 23 | ); 24 | } 25 | }); 26 | 27 | // Enable Composition API 28 | Vue.use(VueCompositionAPI) 29 | 30 | // Register global components 31 | globalComponents(); 32 | 33 | new Vue({ 34 | vuetify, 35 | router, 36 | store, 37 | render: h => h(App), 38 | methods: { 39 | isOnlineChanged(){ 40 | this.$store.commit('globalStore/SET_ONLINE_STATUS', navigator.onLine); 41 | }, 42 | }, 43 | mounted() { 44 | this.$store.commit('globalStore/SET_ONLINE_STATUS', navigator.onLine); 45 | window.addEventListener('online', this.isOnlineChanged); 46 | window.addEventListener('offline', this.isOnlineChanged); 47 | }, 48 | beforeDestroy() { 49 | window.removeEventListener('online', this.isOnlineChanged); 50 | window.removeEventListener('offline', this.isOnlineChanged); 51 | } 52 | }).$mount('#app'); 53 | -------------------------------------------------------------------------------- /2wr-app/src/models/family-plans/Address.js: -------------------------------------------------------------------------------- 1 | export default class Address { 2 | address1 = ""; 3 | address2 = ""; 4 | cityTown = ""; 5 | stateProvince = ""; 6 | postalCode = ""; 7 | } -------------------------------------------------------------------------------- /2wr-app/src/models/family-plans/Child.js: -------------------------------------------------------------------------------- 1 | import Address from "./Address"; 2 | 3 | export default class Child { 4 | id = ""; 5 | name = ""; 6 | birthday = ""; 7 | phoneNumber = ""; 8 | image = ""; 9 | schoolName = ""; 10 | schoolAddress = new Address(); 11 | schoolPhone = "" 12 | relationship = ""; 13 | } -------------------------------------------------------------------------------- /2wr-app/src/models/family-plans/EmergencyContact.js: -------------------------------------------------------------------------------- 1 | export default class EmergencyContact { 2 | id = ""; 3 | fullName = ""; 4 | cellPhone = ""; 5 | email = ""; 6 | schoolInformation = ""; 7 | workInformation = ""; 8 | medicalInformation = ""; 9 | notifyLastLocation = false; 10 | sharePlanWith = false; 11 | } -------------------------------------------------------------------------------- /2wr-app/src/models/family-plans/FamilyPlan.js: -------------------------------------------------------------------------------- 1 | import Address from "./Address"; 2 | 3 | export default class FamilyPlan { 4 | id = ""; 5 | userId = ""; 6 | title = ""; 7 | phoneNumber = ""; 8 | address = new Address(); 9 | emergencyContacts = []; 10 | routes = []; 11 | children = []; 12 | pets = []; 13 | allowAlerts = false; 14 | 15 | } -------------------------------------------------------------------------------- /2wr-app/src/models/family-plans/Pet.js: -------------------------------------------------------------------------------- 1 | export default class Pet { 2 | id = ""; 3 | name = ""; 4 | type = ""; 5 | description = ""; 6 | image = ""; 7 | microchipId = ""; 8 | } -------------------------------------------------------------------------------- /2wr-app/src/models/family-plans/RouteLocation.js: -------------------------------------------------------------------------------- 1 | import Address from "./Address"; 2 | 3 | export default class RouteLocation { 4 | id = ""; 5 | name = ""; 6 | images = []; 7 | instructions = ""; 8 | address = new Address(); 9 | } -------------------------------------------------------------------------------- /2wr-app/src/plugins/vuetify.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuetify from 'vuetify/lib'; 3 | import '@mdi/font/css/materialdesignicons.css'; 4 | import colors from 'vuetify/lib/util/colors'; 5 | import VueRouter from 'vue-router' 6 | 7 | const themeColors = { 8 | lightOrange: "#f99b2c", 9 | darkOrange: "#c14d23", 10 | background: "#f8f1c7" 11 | } 12 | 13 | Vue.use(Vuetify); 14 | Vue.use(VueRouter); 15 | 16 | const vuetify = new Vuetify({ 17 | icons: { 18 | iconfont: 'mdi' 19 | }, 20 | theme: { 21 | themes: { 22 | light: { 23 | primary: themeColors.lightOrange, 24 | secondary: themeColors.darkOrange, 25 | accent: colors.cyan.base, 26 | error: colors.red.base, 27 | warning: colors.amber.base, 28 | info: colors.blueGrey.base, 29 | success: colors.green.base, 30 | background: themeColors.background 31 | } 32 | } 33 | } 34 | }); 35 | 36 | export default vuetify; 37 | -------------------------------------------------------------------------------- /2wr-app/src/register-service-worker.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | 3 | import { register } from 'register-service-worker' 4 | 5 | if (process.env.NODE_ENV === 'production') { 6 | register(`${process.env.BASE_URL}service-worker.js`, { 7 | ready () { 8 | console.log( 9 | 'App is being served from cache by a service worker.\n' + 10 | 'For more details, visit https://goo.gl/AFskqB' 11 | ); 12 | }, 13 | registered () { 14 | console.log('Service worker has been registered.'); 15 | }, 16 | cached () { 17 | console.log('Content has been cached for offline use.'); 18 | }, 19 | updatefound () { 20 | console.log('New content is downloading.'); 21 | }, 22 | updated () { 23 | console.log('New content is available; please refresh.'); 24 | // setTimeout(() => { 25 | // window.location.reload(true); 26 | // }, 1000); 27 | }, 28 | offline () { 29 | console.log('No internet connection found. App is running in offline mode.'); 30 | }, 31 | error (error) { 32 | console.error('Error during service worker registration:', error); 33 | } 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /2wr-app/src/router/familyPlanRoutes.js: -------------------------------------------------------------------------------- 1 | import FamilyPlanLanding from '../views/prepare/family-plans/landing.vue'; 2 | import FamilyPlanView from '../views/prepare/family-plans/view.vue'; 3 | import FamilyPlanContacts from "../views/prepare/family-plans/contacts.vue" 4 | import FamilyPlanDistantContacts from "../views/prepare/family-plans/distant-contacts.vue" 5 | import FamilyPlanRoutes from "../views/prepare/family-plans/routes.vue"; 6 | import FamilyPlanChildren from '@/views/prepare/family-plans/children.vue'; 7 | import FamilyPlanPets from '@/views/prepare/family-plans/pets.vue'; 8 | 9 | export default [ 10 | { 11 | path: '/prepare/familyplan', 12 | name: 'familyplan', 13 | component: FamilyPlanLanding, 14 | meta: { 15 | requiresAuth: true 16 | } 17 | }, 18 | { 19 | path: '/prepare/familyplan/:planId', 20 | name: 'familyplan-view', 21 | component: FamilyPlanView, 22 | props: true, 23 | meta: { 24 | requiresAuth: true 25 | } 26 | }, 27 | { 28 | path: '/prepare/familyplan/:planId/distantcontacts', 29 | name: "familyplan-distantcontacts", 30 | component: FamilyPlanDistantContacts, 31 | props: true, 32 | meta: { 33 | requiresAuth: true 34 | } 35 | }, 36 | { 37 | path: '/prepare/familyplan/:planId/emergencycontacts', 38 | name: "familyplay-contacts", 39 | component: FamilyPlanContacts, 40 | props: true, 41 | meta: { 42 | requiresAuth: true 43 | } 44 | }, 45 | { 46 | path: '/prepare/familyplan/:planId/routes', 47 | name: "familyplay-routes", 48 | component: FamilyPlanRoutes, 49 | props: true, 50 | meta: { 51 | requiresAuth: true 52 | } 53 | }, 54 | { 55 | path: '/prepare/familyplan/:planId/children', 56 | name: "familyplay-children", 57 | component: FamilyPlanChildren, 58 | props: true, 59 | meta: { 60 | requiresAuth: true 61 | } 62 | }, 63 | { 64 | path: '/prepare/familyplan/:planId/pets', 65 | name: "familyplay-pets", 66 | component: FamilyPlanPets, 67 | props: true, 68 | meta: { 69 | requiresAuth: true 70 | } 71 | } 72 | ]; 73 | -------------------------------------------------------------------------------- /2wr-app/src/rules/index.js: -------------------------------------------------------------------------------- 1 | export function required(msg) { 2 | if (!msg) msg = "Required."; 3 | return (v) => !!v || msg; 4 | } 5 | 6 | export function minLength(len, msg) { 7 | if (!msg) msg = "Length Required."; 8 | return (v) => v.length >= len || msg; 9 | } 10 | 11 | export function maxLength(len, msg) { 12 | if (!msg) msg = `Must be less than ${len} characters.` 13 | return (v) => v.length < len || msg; 14 | } 15 | 16 | export function phoneNumber(msg) { 17 | if (!msg) msg = "Must be a valid phone number. (e.g. (404) 555-1212, 404-555-1212)"; 18 | return (v) => !v || /^(\([0-9]{3}\)\s?|[0-9]{3}-)[0-9]{3}-[0-9]{4}$/.test(v) || msg; 19 | } 20 | 21 | 22 | export function email(msg) { 23 | if (!msg) msg = "Must be a valid email."; 24 | return (v) => !v || /^[^@]+@[^@]+\.[^@]+$/.test(v) || msg; 25 | } 26 | 27 | export function zipCode(msg) { 28 | if (!msg) msg = "Must be a valid zipcode."; 29 | return (v) => !v || /^[0-9]{5}(?:-[0-9]{4})?$$/.test(v) || msg; 30 | } 31 | -------------------------------------------------------------------------------- /2wr-app/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | import baseKitStore from './modules/prepare/base-kits/base-kit-store'; 4 | import emergencyKitStore from './modules/prepare/emergency-kits/emergency-kit-store'; 5 | import hazardHuntStore from './modules/prepare/hazards/hazard-hunt-store'; 6 | import hazardInfoStore from './modules/prepare/hazards/hazard-info-store'; 7 | import globalStore from './modules/global/global-store'; 8 | import familyPlansStore from './modules/prepare/family-plans'; 9 | 10 | Vue.use(Vuex); 11 | 12 | const store = new Vuex.Store({ 13 | strict: process.env.NODE_ENV !== 'production', 14 | state: { 15 | isBusy: false, 16 | error: "" 17 | }, 18 | mutations: { 19 | clearBusy: (state) => state.isBusy = false, 20 | setBusy: (state) => state.isBusy = true, 21 | setError: (state, msg) => state.error = msg 22 | }, 23 | // actions: { 24 | 25 | // }, 26 | modules: { 27 | globalStore, 28 | baseKitStore, 29 | emergencyKitStore, 30 | hazardHuntStore, 31 | hazardInfoStore, 32 | familyPlansStore 33 | } 34 | }); 35 | 36 | export default store; 37 | 38 | -------------------------------------------------------------------------------- /2wr-app/src/store/modules/global/global-store.js: -------------------------------------------------------------------------------- 1 | const globalStore = { 2 | namespaced: true, 3 | state: { 4 | online: navigator.onLine 5 | }, 6 | mutations: { 7 | SET_ONLINE_STATUS(state, payload) { 8 | state.online = payload; 9 | } 10 | } 11 | }; 12 | 13 | export default globalStore; -------------------------------------------------------------------------------- /2wr-app/src/store/modules/prepare/base-kits/base-kit-store.js: -------------------------------------------------------------------------------- 1 | import baseKitApi from "../../../../api/base-kit-api"; 2 | import localForage from "localforage"; 3 | 4 | const baseKitStore = { 5 | namespaced: true, 6 | state: { 7 | list: [], 8 | isLoading: false, 9 | loadErrorMessage: null, 10 | selectedKit: null, 11 | }, 12 | mutations: { 13 | SET_LIST(state, payload) { 14 | state.list = payload; 15 | }, 16 | LOAD_START(state) { 17 | state.isLoading = true; 18 | }, 19 | LOAD_SUCCESS(state, payload) { 20 | state.isLoading = false; 21 | state.item = payload; 22 | }, 23 | LOAD_ERROR(state, payload) { 24 | state.isLoading = false; 25 | state.loadErrorMessage = payload; 26 | } 27 | }, 28 | actions: { 29 | async getBaseKitListAsync({ commit, rootState }) { 30 | if (rootState.globalStore.online) { 31 | let response = await baseKitApi.getAll(); 32 | commit("SET_LIST", response.data); 33 | await localForage.setItem("getBaseKitListAsync", response.data); 34 | } else { 35 | var data = await localForage.getItem("getBaseKitListAsync"); 36 | if (data) { 37 | console.log("Serving from cache"); 38 | commit("SET_LIST", data); 39 | } else { 40 | console.log("Offline without data"); 41 | } 42 | } 43 | }, 44 | }, 45 | }; 46 | 47 | export default baseKitStore; 48 | -------------------------------------------------------------------------------- /2wr-app/src/store/modules/prepare/family-plans/getters.js: -------------------------------------------------------------------------------- 1 | export default { 2 | findFamilyPlan: (state) => (id) => { 3 | let found = state.familyPlans.find(item => item.id === id); 4 | return found; 5 | } 6 | } -------------------------------------------------------------------------------- /2wr-app/src/store/modules/prepare/family-plans/index.js: -------------------------------------------------------------------------------- 1 | import state from "./state"; 2 | import mutations from "./mutations"; 3 | import actions from "./actions"; 4 | import getters from "./getters"; 5 | 6 | export default { 7 | namespaced: true, 8 | state, 9 | mutations, 10 | actions, 11 | getters 12 | } -------------------------------------------------------------------------------- /2wr-app/src/store/modules/prepare/family-plans/mutations.js: -------------------------------------------------------------------------------- 1 | export default { 2 | setFamilyPlans: (state, plans) => (state.familyPlans = plans), 3 | setSharedPlans: (state, plans) => (state.sharedPlans = plans), 4 | addToFamilyPlans: (state, newPlan) => 5 | state.familyPlans.splice(state.familyPlans.length, 0, newPlan), 6 | removeFromFamilyPlans: (state, plan) => { 7 | const index = state.familyPlans.indexOf(plan); 8 | if (index > -1) state.familyPlans.splice(index, 1); 9 | }, 10 | replaceContact: (state, { contact, plan }) => { 11 | const index = plan.emergencyContacts.findIndex(i => i.id == contact.id); 12 | plan.emergencyContacts.splice(index, 1, contact); 13 | }, 14 | addContact: (state, { contact, plan }) => { 15 | plan.emergencyContacts.splice(plan.emergencyContacts.length, 0, contact); 16 | }, 17 | replaceRoute: (state, { route, plan }) => { 18 | const index = plan.routeLocations.findIndex(i => i.id == route.id); 19 | plan.routeLocations.splice(index, 1, route); 20 | }, 21 | addRoute: (state, { route, plan }) => { 22 | plan.routeLocations.splice(plan.routeLocations.length, 0, route); 23 | }, 24 | replaceChild: (state, { child, plan }) => { 25 | const index = plan.children.findIndex(i => i.id == child.id); 26 | plan.children.splice(index, 1, child); 27 | }, 28 | addChild: (state, { child, plan }) => { 29 | plan.children.splice(plan.children.length, 0, child); 30 | }, 31 | replacePet: (state, { pet, plan }) => { 32 | const index = plan.pets.findIndex(i => i.id == pet.id); 33 | plan.pets.splice(index, 1, pet); 34 | }, 35 | addPet: (state, { pet, plan }) => { 36 | plan.pets.splice(plan.pets.length, 0, pet); 37 | }, 38 | addPhotoToRoute: (state, { photo, route }) => { 39 | route.images.splice(route.images.length, 0, photo); 40 | }, 41 | addPhotoToChild: (state, { photo, child }) => { 42 | child.image = photo; 43 | }, 44 | addPhotoToPet: (state, { photo, pet }) => { 45 | pet.image = photo; 46 | } 47 | }; 48 | -------------------------------------------------------------------------------- /2wr-app/src/store/modules/prepare/family-plans/state.js: -------------------------------------------------------------------------------- 1 | export default { 2 | familyPlans: [], 3 | sharedPlans: [] 4 | }; -------------------------------------------------------------------------------- /2wr-app/src/store/modules/prepare/hazards/hazard-hunt-store.js: -------------------------------------------------------------------------------- 1 | import api from '../../../../api/hazard-hunt-api'; 2 | import localForage from 'localforage'; 3 | 4 | const CACHE_KEY = 'HazardHunts'; 5 | const SET_LIST = 'SET_LIST'; 6 | const SET_ITEM = 'SET_ITEM'; 7 | 8 | export default { 9 | namespaced: true, 10 | state: { 11 | list: [], 12 | item: null 13 | }, 14 | mutations: { 15 | [SET_LIST](state, payload) { 16 | state.list = payload; 17 | }, 18 | [SET_ITEM](state, payload) { 19 | state.item = payload; 20 | } 21 | }, 22 | actions: { 23 | async getHazardHuntsAsync({ commit, rootState }) { 24 | if (rootState.globalStore.online) { 25 | let response = await api.getDocuments(); 26 | commit(SET_LIST, response.data); 27 | await localForage.setItem(CACHE_KEY, response.data); 28 | } else { 29 | var data = await localForage.getItem(CACHE_KEY) 30 | if (data) { 31 | console.log("Serving from cache"); 32 | commit(SET_LIST, data); 33 | } else { 34 | console.log("Offline without data"); 35 | } 36 | 37 | } 38 | }, 39 | async getHazardHuntAsync({ commit, rootState} , id) { 40 | 41 | try { 42 | commit("setBusy", null, { root: true }); 43 | commit("setError", "", { root: true }); 44 | const itemCacheKey = `${CACHE_KEY}/${id}` 45 | if (rootState.globalStore.online) { 46 | let response = await api.get(id); 47 | commit(SET_ITEM, response.data); 48 | await localForage.setItem(itemCacheKey, response.data); 49 | } else { 50 | var data = await localForage.getItem(itemCacheKey) 51 | if (data) { 52 | console.log("Serving from cache"); 53 | commit(SET_ITEM, data); 54 | } else { 55 | console.log("Offline without data"); 56 | } 57 | } 58 | } catch { 59 | commit("setError", "Could not load hazard hunt.", { root: true }); 60 | } finally { 61 | commit("clearBusy", null, { root: true }); 62 | } 63 | } 64 | } 65 | }; -------------------------------------------------------------------------------- /2wr-app/src/store/modules/prepare/hazards/hazard-info-store.js: -------------------------------------------------------------------------------- 1 | import api from '../../../../api/hazard-info-api'; 2 | import localForage from 'localforage'; 3 | 4 | const CACHE_KEY = 'HazardInfos'; 5 | const SET_LIST = 'SET_LIST'; 6 | const SET_ITEM = 'SET_ITEM'; 7 | 8 | export default { 9 | namespaced: true, 10 | state: { 11 | list: [], 12 | item: null 13 | }, 14 | mutations: { 15 | [SET_LIST](state, payload) { 16 | state.list = payload; 17 | }, 18 | [SET_ITEM](state, payload) { 19 | state.item = payload; 20 | } 21 | }, 22 | actions: { 23 | async getHazardInfosAsync({ commit, rootState }) { 24 | 25 | try { 26 | commit("setBusy", null, { root: true }); 27 | commit("setError", "", { root: true }); 28 | 29 | if (rootState.globalStore.online) { 30 | let response = await api.getAll(); 31 | commit(SET_LIST, response.data); 32 | await localForage.setItem(CACHE_KEY, response.data); 33 | } else { 34 | var data = await localForage.getItem(CACHE_KEY) 35 | if (data) { 36 | console.log("Serving from cache"); 37 | commit(SET_LIST, data); 38 | } else { 39 | console.log("Offline without data"); 40 | } 41 | } 42 | } catch { 43 | commit("setError", "Could not load hazard information.", { root: true }); 44 | } finally { 45 | commit("clearBusy", null, { root: true }); 46 | } 47 | }, 48 | async getHazardInfoAsync({ commit, rootState} , id) { 49 | 50 | try { 51 | commit("setBusy", null, { root: true }); 52 | commit("setError", "", { root: true }); 53 | const itemCacheKey = `${CACHE_KEY}/${id}` 54 | if (rootState.globalStore.online) { 55 | let response = await api.get(id); 56 | commit(SET_ITEM, response.data); 57 | await localForage.setItem(itemCacheKey, response.data); 58 | } else { 59 | var data = await localForage.getItem(itemCacheKey) 60 | if (data) { 61 | console.log("Serving from cache"); 62 | commit(SET_ITEM, data); 63 | } else { 64 | console.log("Offline without data"); 65 | } 66 | } 67 | } catch { 68 | commit("setError", "Could not load hazard information.", { root: true }); 69 | } finally { 70 | commit("clearBusy", null, { root: true }); 71 | } 72 | } 73 | } 74 | }; -------------------------------------------------------------------------------- /2wr-app/src/views/prepare/emergency-kits/emergency-kit-build.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | -------------------------------------------------------------------------------- /2wr-app/src/views/prepare/emergency-kits/emergency-kit-details.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | -------------------------------------------------------------------------------- /2wr-app/src/views/prepare/emergency-kits/emergency-kit-listing.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | -------------------------------------------------------------------------------- /2wr-app/src/views/prepare/family-plans/children.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /2wr-app/src/views/prepare/family-plans/contacts.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 14 | -------------------------------------------------------------------------------- /2wr-app/src/views/prepare/family-plans/distant-contacts.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 14 | -------------------------------------------------------------------------------- /2wr-app/src/views/prepare/family-plans/landing.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /2wr-app/src/views/prepare/family-plans/pets.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /2wr-app/src/views/prepare/family-plans/routes.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 14 | -------------------------------------------------------------------------------- /2wr-app/src/views/prepare/family-plans/view.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 16 | 17 | -------------------------------------------------------------------------------- /2wr-app/src/views/prepare/hazards/hazard-hunt-list-view.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | -------------------------------------------------------------------------------- /2wr-app/src/views/prepare/hazards/hazard-hunt-view.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | -------------------------------------------------------------------------------- /2wr-app/src/views/prepare/hazards/hazard-info-list-view.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | -------------------------------------------------------------------------------- /2wr-app/src/views/prepare/hazards/hazard-info-view.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | -------------------------------------------------------------------------------- /2wr-app/src/views/prepare/make-a-plan/make-a-plan.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 15 | -------------------------------------------------------------------------------- /2wr-app/src/views/prepare/prepare.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /2wr-app/src/views/recent/recent.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /2wr-app/src/views/settings/settings.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /2wr-app/src/views/welcome/welcome.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /2wr-app/tests/global-setup.js: -------------------------------------------------------------------------------- 1 | // global-setup.js 2 | const { chromium, expect } = require("@playwright/test"); 3 | 4 | module.exports = async () => { 5 | const browser = await chromium.launch(); 6 | const page = await browser.newPage(); 7 | await page.goto("http://localhost:8080/"); 8 | 9 | // Save not signed-in state to 'newuser-storageState.json'. 10 | await page 11 | .context() 12 | .storageState({ path: "./tests/_storagestate/newuser-storageState.json" }); 13 | 14 | await page.getByTestId("welcome-next-button").click(); 15 | await expect( 16 | page.getByRole("heading", { name: "You and earthquake risk" }) 17 | ).toBeVisible(); 18 | await page.getByTestId("welcome-next-button").click(); 19 | await expect( 20 | page.getByRole("heading", { name: "Let's get started!" }) 21 | ).toBeVisible(); 22 | await page.getByTestId("welcome-next-button").click(); 23 | 24 | await page 25 | .getByLabel("Email address") 26 | .fill(process.env.TWO_WEEKS_READY_E2E_TEST_USERNAME); 27 | await page 28 | .getByLabel("Password") 29 | .fill(process.env.TWO_WEEKS_READY_E2E_TEST_PASSWORD); 30 | 31 | await page.getByRole('button', { name: 'Continue', exact: true }).click(); 32 | await page.waitForURL("http://localhost:8080/prepare"); 33 | 34 | // Save signed-in state to 'storageState.json'. 35 | await page 36 | .context() 37 | .storageState({ path: "./tests/_storagestate/storageState.json" }); 38 | 39 | // TODO: Add a environment variable to allow for optional seeding of data by calling admin APIs 40 | // const token = await page.evaluate(async () =>await document.getElementById("app").__vue__.$auth.getTokenSilently()); 41 | // const response = await page.request.post("http://localhost:7071/api/hazardinfo-create", { 42 | // data: { 43 | // name: "Earthquake", 44 | // beforeSafetyDetails: "Practice how to drop, cover, and hold on" 45 | // }, 46 | // headers: { 47 | // 'Authorization': `Bearer ${token}`, 48 | // }, 49 | // }); 50 | // expect(response.ok()).toBeTruthy(); 51 | await browser.close(); 52 | }; 53 | -------------------------------------------------------------------------------- /2wr-app/tests/welcome.spec.js: -------------------------------------------------------------------------------- 1 | const { expect, test, chromium } = require("@playwright/test"); 2 | const { injectAxe, checkA11y } = require("axe-playwright"); 3 | 4 | test.use({ storageState: "./tests/_storagestate/newuser-storageState.json" }); 5 | 6 | test.describe("Welcome page accessibility test", () => { 7 | let browser; 8 | let page; 9 | 10 | test.beforeAll(async () => { 11 | browser = await chromium.launch(); 12 | page = await browser.newPage(); 13 | await page.goto("./welcome/"); 14 | await injectAxe(page); 15 | }); 16 | 17 | test("Check Accessibility", async () => { 18 | await checkA11y(page, null, { 19 | axeOptions: {}, 20 | detailedReport: true, 21 | detailedReportOptions: { 22 | html: true 23 | } 24 | }); 25 | }); 26 | }); 27 | 28 | test("Welcome page loads", async ({ page }) => { 29 | await page.goto("./"); 30 | 31 | await expect(page).toHaveURL(/.*welcome/); 32 | }); 33 | -------------------------------------------------------------------------------- /2wr-app/vue.config.js: -------------------------------------------------------------------------------- 1 | const Dotenv = require("dotenv-webpack"); 2 | 3 | module.exports = { 4 | css: { 5 | sourceMap: true 6 | }, 7 | pwa: { 8 | workboxPluginMode: "InjectManifest", 9 | workboxOptions: { 10 | swSrc: "public/service-worker.js" 11 | }, 12 | manifestOptions: { 13 | name: "Two Weeks Ready", 14 | short_name: "Two Weeks Ready", 15 | description: 16 | "Support preparedness and alerting related to emergency situations.", 17 | start_url: "/index.html", 18 | background_color: "#F7F1C7", 19 | theme_color: "#D75727", 20 | icons: [ 21 | { 22 | src: "./img/icons/android-chrome-192x192.png", 23 | sizes: "192x192", 24 | type: "image/png" 25 | }, 26 | { 27 | src: "./img/icons/android-chrome-512x512.png", 28 | sizes: "512x512", 29 | type: "image/png" 30 | }, 31 | { 32 | src: "./img/icons/android-chrome-maskable-192x192.png", 33 | sizes: "192x192", 34 | type: "image/png", 35 | purpose: "maskable" 36 | }, 37 | { 38 | src: "./img/icons/android-chrome-maskable-512x512.png", 39 | sizes: "512x512", 40 | type: "image/png", 41 | purpose: "maskable" 42 | }, 43 | { 44 | src: "./img/icons/apple-touch-icon-60x60.png", 45 | sizes: "60x60", 46 | type: "image/png" 47 | }, 48 | { 49 | src: "./img/icons/apple-touch-icon-76x76.png", 50 | sizes: "76x76", 51 | type: "image/png" 52 | }, 53 | { 54 | src: "./img/icons/apple-touch-icon-120x120.png", 55 | sizes: "120x120", 56 | type: "image/png" 57 | }, 58 | { 59 | src: "./img/icons/apple-touch-icon-152x152.png", 60 | sizes: "152x152", 61 | type: "image/png" 62 | }, 63 | { 64 | src: "./img/icons/apple-touch-icon-180x180.png", 65 | sizes: "180x180", 66 | type: "image/png" 67 | }, 68 | { 69 | src: "./img/icons/apple-touch-icon.png", 70 | sizes: "180x180", 71 | type: "image/png" 72 | }, 73 | { 74 | src: "./img/icons/favicon-16x16.png", 75 | sizes: "16x16", 76 | type: "image/png" 77 | }, 78 | { 79 | src: "./img/icons/favicon-32x32.png", 80 | sizes: "32x32", 81 | type: "image/png" 82 | }, 83 | { 84 | src: "./img/icons/msapplication-icon-144x144.png", 85 | sizes: "144x144", 86 | type: "image/png" 87 | }, 88 | { 89 | src: "./img/icons/mstile-150x150.png", 90 | sizes: "150x150", 91 | type: "image/png" 92 | } 93 | ] 94 | } 95 | }, 96 | configureWebpack: { 97 | plugins: [new Dotenv()] 98 | }, 99 | transpileDependencies: ["vuetify"] 100 | }; 101 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Humanitarian Toolbox 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /TwoWeeksReady.Common/EmergencyKits/BaseKit.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace TwoWeeksReady.Common.EmergencyKits 5 | { 6 | public class BaseKit 7 | { 8 | [JsonProperty(PropertyName = "id")] 9 | public string Id { get; set; } 10 | 11 | [JsonProperty(PropertyName = "name")] 12 | public string Name { get; set; } 13 | 14 | [JsonProperty(PropertyName = "description")] 15 | public string Description { get; set; } 16 | 17 | [JsonProperty(PropertyName = "iconUrl")] 18 | public string IconUrl { get; set; } 19 | 20 | [JsonProperty(PropertyName = "items")] 21 | public List Items { get; set; } = new List(); 22 | } 23 | } -------------------------------------------------------------------------------- /TwoWeeksReady.Common/EmergencyKits/BaseKitItem.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace TwoWeeksReady.Common.EmergencyKits 4 | { 5 | public class BaseKitItem 6 | { 7 | [JsonProperty(PropertyName = "id")] 8 | public string Id { get; set; } 9 | 10 | [JsonProperty(PropertyName = "name")] 11 | public string Name { get; set; } 12 | 13 | [JsonProperty(PropertyName = "description")] 14 | public string Description { get; set; } 15 | 16 | [JsonProperty(PropertyName = "quantityPerAdult")] 17 | public int QuantityPerAdult { get; set; } //per adult 18 | 19 | [JsonProperty(PropertyName = "quantityPerChild")] 20 | public int QuantityPerChild { get; set; } //per child 21 | 22 | [JsonProperty(PropertyName = "quantityPerPet")] 23 | public int QuantityPerPet { get; set; } //per pet 24 | 25 | [JsonProperty(PropertyName = "quantityUnit")] 26 | public string QuantityUnit { get; set; } //measurement unit, 14 days 27 | } 28 | } -------------------------------------------------------------------------------- /TwoWeeksReady.Common/EmergencyKits/Kit.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System.Collections.Generic; 3 | 4 | namespace TwoWeeksReady.Common.EmergencyKits 5 | { 6 | public class Kit 7 | { 8 | [JsonProperty(PropertyName = "id")] 9 | public string Id { get; set; } 10 | 11 | [JsonProperty(PropertyName = "baseKitId")] 12 | public string BaseKitId { get; set; } 13 | 14 | [JsonProperty(PropertyName = "userId")] 15 | public string UserId { get; set; } 16 | 17 | [JsonProperty(PropertyName = "name")] 18 | public string Name { get; set; } 19 | 20 | [JsonProperty(PropertyName = "kitItems")] 21 | public List Items { get; set; } = new List(); 22 | } 23 | } -------------------------------------------------------------------------------- /TwoWeeksReady.Common/EmergencyKits/KitItem.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace TwoWeeksReady.Common.EmergencyKits 4 | { 5 | public class KitItem 6 | { 7 | [JsonProperty(PropertyName = "id")] 8 | public string Id { get; set; } 9 | 10 | [JsonProperty(PropertyName = "baseKitItemId")] 11 | public string BaseKitItemId { get; set; } 12 | 13 | [JsonProperty(PropertyName = "userId")] 14 | public string UserId { get; set; } 15 | 16 | [JsonProperty(PropertyName = "name")] 17 | public string Name { get; set; } 18 | 19 | [JsonProperty(PropertyName = "description")] 20 | public string Description { get; set; } 21 | 22 | [JsonProperty(PropertyName = "quantity")] 23 | public int Quantity { get; set; } 24 | 25 | [JsonProperty(PropertyName = "quantityUnit")] 26 | public string QuantityUnit { get; set; } 27 | 28 | [JsonProperty(PropertyName = "photo")] 29 | public string Photo { get; set; } // URL ? 30 | 31 | [JsonProperty(PropertyName = "isAvailableInKit")] 32 | public bool IsAvailableInKit { get; set; } //checklist for user to see if they have everything they need. 33 | } 34 | } -------------------------------------------------------------------------------- /TwoWeeksReady.Common/FamilyMembers/FamilyMember.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace TwoWeeksReady.Common.FamilyMembers 4 | { 5 | public class FamilyMember 6 | { 7 | public Guid Id { get; set; } 8 | public string Name { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /TwoWeeksReady.Common/FamilyPlans/Address.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace TwoWeeksReady.Common.FamilyPlans 4 | { 5 | public class Address 6 | { 7 | [JsonProperty(PropertyName = "address1")] 8 | public string Address1 { get; set; } 9 | [JsonProperty(PropertyName = "address2")] 10 | public string Address2 { get; set; } 11 | [JsonProperty(PropertyName = "cityTown")] 12 | public string CityTown { get; set; } 13 | [JsonProperty(PropertyName = "stateProvince")] 14 | public string StateProvince { get; set; } 15 | [JsonProperty(PropertyName = "postalCode")] 16 | public string PostalCode { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /TwoWeeksReady.Common/FamilyPlans/Child.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Newtonsoft.Json; 3 | 4 | namespace TwoWeeksReady.Common.FamilyPlans 5 | { 6 | public class Child 7 | { 8 | [JsonProperty("id")] 9 | public string Id { get; set; } 10 | [JsonProperty("name")] 11 | public string Name { get; set; } 12 | [JsonProperty("birthday")] 13 | public DateTime Birthday { get; set; } 14 | [JsonProperty("phoneNumber")] 15 | public string PhoneNumber { get; set; } 16 | [JsonProperty("image")] 17 | public string Image { get; set; } 18 | [JsonProperty("schoolName")] 19 | public string SchoolName { get; set; } 20 | [JsonProperty("schoolAddress")] 21 | public Address SchoolAddress { get; set; } 22 | [JsonProperty("schoolPhone")] 23 | public string SchoolPhone { get; set; } 24 | [JsonProperty("relationship")] 25 | public string Relationship { get; set; } 26 | 27 | } 28 | } -------------------------------------------------------------------------------- /TwoWeeksReady.Common/FamilyPlans/Contact.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace TwoWeeksReady.Common.FamilyPlans 4 | { 5 | public class Contact 6 | { 7 | [JsonProperty("id")] 8 | public string Id { get; set; } 9 | [JsonProperty("fullName")] 10 | public string FullName { get; set; } 11 | [JsonProperty("cellPhone")] 12 | public string CellPhone { get; set; } 13 | [JsonProperty("email")] 14 | public string Email { get; set; } 15 | [JsonProperty("schoolInformation")] 16 | public string SchoolInformation { get; set; } 17 | [JsonProperty("workInformation")] 18 | public string WorkInformation { get; set; } 19 | [JsonProperty("medicalInformation")] 20 | public string MedicalInformation { get; set; } 21 | [JsonProperty("notifyLastLocation")] 22 | public bool NotifyLastLocation { get; set; } 23 | [JsonProperty("sharePlanWith")] 24 | public bool SharePlanWith { get; set; } 25 | [JsonProperty("distant")] 26 | public bool Distant { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /TwoWeeksReady.Common/FamilyPlans/FamilyPlan.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Newtonsoft.Json; 4 | 5 | namespace TwoWeeksReady.Common.FamilyPlans 6 | { 7 | public class FamilyPlan 8 | { 9 | [JsonProperty("id")] 10 | public string Id { get; set; } 11 | 12 | [JsonProperty("userid")] 13 | public string UserId { get; set; } 14 | 15 | [JsonProperty("title")] 16 | public string Title { get; set; } 17 | 18 | [JsonProperty("address")] 19 | public Address Address { get; set; } 20 | 21 | [JsonProperty("phoneNumber")] 22 | public string PhoneNumber { get; set; } 23 | 24 | [JsonProperty("allowAlerts")] 25 | public bool AllowAlerts { get; set; } 26 | 27 | [JsonProperty("emergencyContacts")] 28 | public List EmergencyContacts { get; set; } = new List(); 29 | 30 | [JsonProperty("routeLocations")] 31 | public List RouteLocations { get; set; } = new List(); 32 | 33 | [JsonProperty("children")] 34 | public List Children { get; set; } = new List(); 35 | 36 | [JsonProperty("pets")] 37 | public List Pets { get; set; } = new List(); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /TwoWeeksReady.Common/FamilyPlans/Pet.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace TwoWeeksReady.Common.FamilyPlans 4 | { 5 | public class Pet 6 | { 7 | [JsonProperty("id")] 8 | public string Id { get; set; } 9 | [JsonProperty("name")] 10 | public string Name { get; set; } 11 | [JsonProperty("type")] 12 | public string Type { get; set; } 13 | [JsonProperty("description")] 14 | public string Description { get; set; } 15 | [JsonProperty("image")] 16 | public string Image { get; set; } 17 | [JsonProperty("microchipId")] 18 | public string MicrochipId { get; set; } 19 | 20 | } 21 | } -------------------------------------------------------------------------------- /TwoWeeksReady.Common/FamilyPlans/RouteLocation.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | 4 | namespace TwoWeeksReady.Common.FamilyPlans 5 | { 6 | public class RouteLocation 7 | { 8 | [JsonProperty("id")] 9 | public string Id { get; set; } 10 | [JsonProperty("name")] 11 | public string Name { get; set; } 12 | [JsonProperty("images")] 13 | public List Images { get; set; } 14 | [JsonProperty("instructions")] 15 | public string Instructions { get; set; } 16 | [JsonProperty("address")] 17 | public Address Address { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /TwoWeeksReady.Common/FamilyPlans/WalkThroughStep.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace TwoWeeksReady.Common.FamilyPlans 4 | { 5 | public class WalkThroughStep 6 | { 7 | public List RouteLocations { get; set; } 8 | public string Instructions { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /TwoWeeksReady.Common/Hazards/HazardBaseInfo.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | public class HazardBaseInfo 4 | { 5 | [JsonProperty(PropertyName = "id")] 6 | public string Id { get; set; } 7 | 8 | [JsonProperty(PropertyName = "name")] 9 | public string Name { get; set; } 10 | 11 | [JsonProperty(PropertyName = "description")] 12 | public string Description { get; set; } 13 | 14 | [JsonProperty(PropertyName = "iconUrl")] 15 | public string IconUrl {get; set;} 16 | 17 | /// 18 | /// URL of image or video describing the hazard 19 | /// 20 | [JsonProperty(PropertyName = "mediaUrl")] 21 | public string MediaUrl { get; set; } 22 | 23 | [JsonProperty(PropertyName = "externalLinks")] 24 | public string[] ExternalLinks { get; set; } 25 | 26 | /// 27 | /// HTML used in the Before section of the UI for this Hazard 28 | /// 29 | [JsonProperty(PropertyName = "beforeSafetyDetails")] 30 | public string BeforeSafetyDetails {get; set;} 31 | 32 | /// 33 | /// HTML used in the During section of the UI for this Hazard 34 | /// 35 | [JsonProperty(PropertyName = "duringSafetyDetails")] 36 | public string DuringSafetyDetails {get; set;} 37 | 38 | /// 39 | /// HTML used in the After section of the UI for this Hazard 40 | /// 41 | [JsonProperty(PropertyName = "afterSafetyDetails")] 42 | public string AfterSafetyDetails {get; set;} 43 | } -------------------------------------------------------------------------------- /TwoWeeksReady.Common/Hazards/HazardHunt.cs: -------------------------------------------------------------------------------- 1 | public class HazardHunt : HazardBaseInfo 2 | { 3 | 4 | } -------------------------------------------------------------------------------- /TwoWeeksReady.Common/Hazards/HazardInfo.cs: -------------------------------------------------------------------------------- 1 | public class HazardInfo : HazardBaseInfo 2 | { 3 | 4 | } -------------------------------------------------------------------------------- /TwoWeeksReady.Common/TwoWeeksReady.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/App.razor: -------------------------------------------------------------------------------- 1 | @using TwoWeeksReady.Admin.Security 2 | @inject TokenProvider Service 3 | 4 | 5 | 6 | 7 | 8 | 9 |

Determining session state, please wait...

10 |
11 | 12 |

Sorry

13 |

You're not authorized to reach this page. You need to log in and must be an admin.

14 |
15 |
16 |
17 | 18 | 19 |

Sorry, there's nothing at this address.

20 |
21 |
22 |
23 |
24 | 25 | @code { 26 | 27 | [Parameter] 28 | public TokenProvider InitialState { get; set; } 29 | 30 | protected override void OnInitialized() 31 | { 32 | Service.AccessToken = InitialState.AccessToken; 33 | base.OnInitialized(); 34 | } 35 | } -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Components/KitItemDisplay.razor: -------------------------------------------------------------------------------- 1 | @inject IRepository repository 2 | 3 |
4 |
5 |
6 |
7 | 8 | 12 |
13 |
14 | 15 | 19 |
20 |
21 | 22 | 26 |
27 |
28 | 29 | 33 |
34 |
35 | 36 | 40 |
41 |
42 | 43 | 47 |
48 |
49 |
50 |
51 | 52 | @code { 53 | [Parameter] 54 | public BaseKitItem Item { get; set; } 55 | } 56 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Data/ClientImage.cs: -------------------------------------------------------------------------------- 1 | namespace TwoWeeksReady.Admin.Data 2 | { 3 | public class ClientImage 4 | { 5 | public string RelativePath { get; set; } 6 | public string AbsolutePath { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Data/ClientImageService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using System.IO; 3 | using System.Linq; 4 | 5 | namespace TwoWeeksReady.Admin.Data 6 | { 7 | /// 8 | /// Provides a list of image that are available within the 2wr client app. 9 | /// These are use in Hazard Info and in Base Kits 10 | /// 11 | public class ClientImageService 12 | { 13 | public readonly IConfiguration _configuration; 14 | public readonly ClientImage[] clientImages; 15 | 16 | public ClientImageService(IConfiguration configuration) 17 | { 18 | _configuration = configuration; 19 | 20 | var imagePaths = File.ReadAllLines("./client-images.txt"); 21 | var appUrl = _configuration["2wrAppUrl"].TrimEnd('/'); 22 | 23 | clientImages = imagePaths 24 | .Select(i => i.Replace("\\", "/")) 25 | .Select(i => new ClientImage 26 | { 27 | AbsolutePath = ToAbsolutePath(i), 28 | RelativePath = i 29 | }).ToArray(); 30 | } 31 | 32 | 33 | public ClientImage[] Images => clientImages; 34 | 35 | public string ToAbsolutePath(string relativeImagePath) 36 | { 37 | var appUrl = _configuration["2wrAppUrl"].TrimEnd('/'); 38 | if (string.IsNullOrEmpty(relativeImagePath)) 39 | { 40 | return appUrl; 41 | } 42 | 43 | return $"{appUrl}/{relativeImagePath.TrimStart('/')}"; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Data/IRepository.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Threading.Tasks; 3 | using TwoWeeksReady.Common.EmergencyKits; 4 | 5 | namespace TwoWeeksReady.Admin.Data 6 | { 7 | public interface IRepository 8 | { 9 | Task> GetAllBaseKits(); 10 | Task GetBaseKitById(string id); 11 | Task CreateBaseKit(BaseKit kit); 12 | Task SaveBaseKit(BaseKit kit); 13 | Task DeleteBaseKit(string id); 14 | 15 | Task> GetAllHazardHunts(); 16 | Task GetHazardHuntById(string id); 17 | Task CreateHazardHunt(HazardHunt hazardHunt); 18 | Task SaveHazardHunt(HazardHunt hazardHunt); 19 | Task DeleteHazardHunt(string id); 20 | 21 | Task> GetAllHazardInfos(); 22 | Task GetHazardInfoById(string id); 23 | Task CreateHazardInfo(HazardInfo hazardInfo); 24 | Task SaveHazardInfo(HazardInfo hazardInfo); 25 | Task DeleteHazardInfo(string id); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Pages/Error.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model TwoWeeksReady.Admin.Pages.ErrorModel 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | Error 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |

Error.

19 |

An error occurred while processing your request.

20 | 21 | @if (Model.ShowRequestId) 22 | { 23 |

24 | Request ID: @Model.RequestId 25 |

26 | } 27 | 28 |

Development Mode

29 |

30 | Swapping to the Development environment displays detailed information about the error that occurred. 31 |

32 |

33 | The Development environment shouldn't be enabled for deployed applications. 34 | It can result in displaying sensitive information from exceptions to end users. 35 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development 36 | and restarting the app. 37 |

38 |
39 |
40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Pages/Error.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.AspNetCore.Mvc.RazorPages; 8 | using Microsoft.Extensions.Logging; 9 | 10 | namespace TwoWeeksReady.Admin.Pages 11 | { 12 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)] 13 | [IgnoreAntiforgeryToken] 14 | public class ErrorModel : PageModel 15 | { 16 | public string RequestId { get; set; } 17 | 18 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId); 19 | 20 | private readonly ILogger _logger; 21 | 22 | public ErrorModel(ILogger logger) 23 | { 24 | _logger = logger; 25 | } 26 | 27 | public void OnGet() 28 | { 29 | RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Pages/HazardHunts/List.razor: -------------------------------------------------------------------------------- 1 | @page "/HazardHunts/" 2 | @attribute [Authorize(Roles = "admin")] 3 | 4 | @inject IRepository Repository 5 |

Administer Hazard Hunt for Two Weeks Ready

6 | 7 | @if (_HazardHunts != null && _HazardHunts.Any()) 8 | { 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | @foreach (var hazard in _HazardHunts) 18 | { 19 | 20 | 21 | 26 | 27 | } 28 | 29 | 30 |
Name
22 | 23 | @hazard.Name 24 | 25 |
31 | 32 | } 33 | else 34 | { 35 |

No Hazards defined.

36 | Add New Hazard 37 | } 38 | 39 | @code { 40 | private IEnumerable _HazardHunts { get; set; } 41 | 42 | protected override async Task OnInitializedAsync() 43 | { 44 | 45 | try { 46 | _HazardHunts = await Repository.GetAllHazardHunts(); 47 | } catch (NotImplementedException) { 48 | // Application is still growing, let's not throw an error yet 49 | _HazardHunts = Enumerable.Empty(); 50 | } 51 | 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Pages/HazardInfos/List.razor: -------------------------------------------------------------------------------- 1 | @page "/HazardInfos/" 2 | @attribute [Authorize(Roles = "admin")] 3 | @inject IRepository Repository 4 |

Administer Hazard Info

5 | 6 | @if (_HazardInfos != null && _HazardInfos.Any()) 7 | { 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | @foreach (var hazard in _HazardInfos) 17 | { 18 | 19 | 20 | 25 | 26 | } 27 | 28 | 29 |
Name
21 | 22 | @hazard.Name 23 | 24 |
30 | Add New Hazard 31 | 32 | } 33 | else if (_HazardInfos == null) 34 | { 35 |

Loading....

36 | } 37 | else 38 | { 39 |

No hazard infos defined

40 | Add New Hazard 41 | } 42 | 43 | @code { 44 | private IEnumerable _HazardInfos { get; set; } 45 | 46 | protected override async Task OnInitializedAsync() 47 | { 48 | 49 | _HazardInfos = await Repository.GetAllHazardInfos(); 50 | 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Pages/Index.razor: -------------------------------------------------------------------------------- 1 | @page "/" 2 | 3 |

Homepage

4 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Pages/Kits/Details.razor: -------------------------------------------------------------------------------- 1 | @page "/Kits/{id}" 2 | @page "/Kits/new" 3 | @attribute [Authorize(Roles = "admin")] 4 | @inject IRepository repository 5 | @inject IJSRuntime JS 6 | @inject ClientImageService clientImages 7 | 8 | @if (Kit != null) 9 | { 10 |

Kit Details :: @Kit.Name

11 | 12 |
13 | 14 |
15 | 16 | 17 |
18 |
19 | 20 | 22 |
23 |
24 | 25 | 26 | 27 | @foreach (var image in clientImages.Images) 28 | { 29 | 30 | } 31 | 32 | 33 | 34 |
35 |
36 |
37 | 38 |
39 | 40 | @foreach (var item in Kit.Items) 41 | { 42 | 43 | } 44 | 45 |
46 | 47 | 48 | } 49 | else 50 | { 51 |

Loading...

52 | } 53 | 54 | 55 | @code { 56 | 57 | [Parameter] 58 | public string Id { get; set; } 59 | 60 | public BaseKit Kit { get; set; } 61 | 62 | public void AddKitItem() 63 | { 64 | if (Kit != null && Kit.Items != null) 65 | { 66 | Kit.Items.Add(new BaseKitItem { Id = Guid.NewGuid().ToString() }); 67 | } 68 | } 69 | 70 | public async Task SaveBaseKit() 71 | { 72 | if (Kit != null) 73 | { 74 | if (string.IsNullOrEmpty(Kit.Id)) 75 | { 76 | Kit = await repository.CreateBaseKit(Kit); 77 | } 78 | else 79 | { 80 | Kit = await repository.SaveBaseKit(Kit); 81 | } 82 | 83 | await JS.InvokeVoidAsync("alert", new object[] { "Base Kit Saved" }); 84 | } 85 | } 86 | 87 | protected override async Task OnInitializedAsync() 88 | { 89 | if (string.IsNullOrEmpty(Id)) 90 | { 91 | Kit = new BaseKit(); 92 | } 93 | else 94 | { 95 | Kit = await repository.GetBaseKitById(Id); 96 | } 97 | await base.OnInitializedAsync(); 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Pages/Kits/List.razor: -------------------------------------------------------------------------------- 1 | @page "/Kits/" 2 | @attribute [Authorize (Roles = "admin")] 3 | @inject IRepository Repository 4 | @inject ClientImageService clientImages 5 | 6 |

Administer Base Kits

7 | 8 | @if (BaseKits != null && BaseKits.Any()) 9 | { 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | @foreach (var kit in BaseKits) 20 | { 21 | 22 | 27 | 28 | 29 | } 30 | 31 | 32 |
NameLine Item Count
23 | 24 | @kit.Name 25 | 26 | @kit.Items.Count()
33 | Add New Kit 34 | } 35 | else if (BaseKits == null) 36 | { 37 |

Loading....

38 | } 39 | else 40 | { 41 |

No base kits defined.

42 | Add New Kit 43 | } 44 | 45 | @code { 46 | 47 | public IEnumerable BaseKits { get; set; } 48 | 49 | protected override async Task OnInitializedAsync() 50 | { 51 | 52 | try { 53 | BaseKits = await Repository.GetAllBaseKits(); 54 | } catch (NotImplementedException) 55 | { 56 | // do nothing for now... site is still growing 57 | BaseKits = Enumerable.Empty(); 58 | } 59 | 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Pages/Login.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model TwoWeeksReady.Admin.Page.LoginModel 3 | @{ 4 | } 5 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Pages/Login.cshtml.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.AspNetCore.Authentication; 3 | using Microsoft.AspNetCore.Mvc.RazorPages; 4 | 5 | namespace TwoWeeksReady.Admin.Page 6 | { 7 | public class LoginModel : PageModel 8 | { 9 | public async Task OnGet(string redirectUri) 10 | { 11 | await HttpContext.ChallengeAsync("Auth0", new AuthenticationProperties 12 | { 13 | RedirectUri = redirectUri 14 | }); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Pages/Logout.cshtml: -------------------------------------------------------------------------------- 1 | @page 2 | @model TwoWeeksReady.Admin.Page.LogoutModel 3 | @{ 4 | } 5 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Pages/Logout.cshtml.cs: -------------------------------------------------------------------------------- 1 | 2 | using System.Threading.Tasks; 3 | using Microsoft.AspNetCore.Authentication; 4 | using Microsoft.AspNetCore.Authentication.Cookies; 5 | using Microsoft.AspNetCore.Mvc.RazorPages; 6 | 7 | namespace TwoWeeksReady.Admin.Page 8 | { 9 | public class LogoutModel : PageModel 10 | { 11 | public async Task OnGet() 12 | { 13 | await HttpContext.SignOutAsync("Auth0", new AuthenticationProperties { RedirectUri = "/"}); 14 | await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Pages/_Host.cshtml: -------------------------------------------------------------------------------- 1 | @page "/" 2 | @namespace TwoWeeksReady.Admin.Pages 3 | @using TwoWeeksReady.Admin.Security 4 | @using Microsoft.AspNetCore.Authentication 5 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 6 | @{ 7 | Layout = null; 8 | } 9 | 10 | 11 | 12 | 13 | 14 | 15 | Two Weeks Ready :: Application Administration 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | @{ 25 | var token = new TokenProvider 26 | { 27 | AccessToken = await HttpContext.GetTokenAsync("access_token") 28 | }; 29 | } 30 | 31 | 32 | 33 | 34 |
35 | 36 | An error has occurred. This application may no longer respond until reloaded. 37 | 38 | 39 | An unhandled exception has occurred. See browser dev tools for details. 40 | 41 | Reload 42 | 🗙 43 |
44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components; 2 | using Microsoft.AspNetCore.Components.Web; 3 | using TwoWeeksReady.Admin; 4 | 5 | var builder = WebApplication.CreateBuilder(args); 6 | 7 | // Configure the container. 8 | builder.Services.ConfigureServices(builder.Configuration); 9 | 10 | var app = builder.Build(); 11 | 12 | // Configure the HTTP request pipeline. 13 | if (!app.Environment.IsDevelopment()) 14 | { 15 | app.UseExceptionHandler("/Error"); 16 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. 17 | app.UseHsts(); 18 | } 19 | 20 | app.UseHttpsRedirection(); 21 | app.UseStaticFiles(); 22 | 23 | app.UseRouting(); 24 | 25 | app.UseCookiePolicy(); 26 | app.UseAuthentication(); 27 | app.UseAuthorization(); 28 | 29 | app.MapBlazorHub(); 30 | app.MapFallbackToPage("/_Host"); 31 | 32 | app.Run(); 33 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:54838", 7 | "sslPort": 44379 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "adminweb": { 19 | "commandName": "Project", 20 | "dotnetRunMessages": "true", 21 | "launchBrowser": true, 22 | "applicationUrl": "https://localhost:5001;http://localhost:5000", 23 | "environmentVariables": { 24 | "ASPNETCORE_ENVIRONMENT": "Development" 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Security/TokenProvider.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Components.Authorization; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | 5 | namespace TwoWeeksReady.Admin.Security 6 | { 7 | public class TokenProvider 8 | { 9 | public string AccessToken { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Shared/AccessControl.razor: -------------------------------------------------------------------------------- 1 | 2 | 3 | Logout 4 | 5 | 6 | Log in 7 | 8 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Shared/MainLayout.razor: -------------------------------------------------------------------------------- 1 | @inherits LayoutComponentBase 2 | 3 |
4 | 7 | 8 |
9 |
10 | 11 | About HtBox 12 |
13 | 14 |
15 | @Body 16 |
17 |
18 |
19 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Shared/MainLayout.razor.css: -------------------------------------------------------------------------------- 1 | .page { 2 | position: relative; 3 | display: flex; 4 | flex-direction: column; 5 | } 6 | 7 | .main { 8 | flex: 1; 9 | } 10 | 11 | .sidebar { 12 | background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); 13 | } 14 | 15 | .top-row { 16 | background-color: #f7f7f7; 17 | border-bottom: 1px solid #d6d5d5; 18 | justify-content: flex-end; 19 | height: 3.5rem; 20 | display: flex; 21 | align-items: center; 22 | } 23 | 24 | .top-row ::deep a, .top-row .btn-link { 25 | white-space: nowrap; 26 | margin-left: 1.5rem; 27 | } 28 | 29 | .top-row a:first-child { 30 | overflow: hidden; 31 | text-overflow: ellipsis; 32 | } 33 | 34 | @media (max-width: 640.98px) { 35 | .top-row:not(.auth) { 36 | display: none; 37 | } 38 | 39 | .top-row.auth { 40 | justify-content: space-between; 41 | } 42 | 43 | .top-row a, .top-row .btn-link { 44 | margin-left: 0; 45 | } 46 | } 47 | 48 | @media (min-width: 641px) { 49 | .page { 50 | flex-direction: row; 51 | } 52 | 53 | .sidebar { 54 | width: 250px; 55 | height: 100vh; 56 | position: sticky; 57 | top: 0; 58 | } 59 | 60 | .top-row { 61 | position: sticky; 62 | top: 0; 63 | z-index: 1; 64 | } 65 | 66 | .main > div { 67 | padding-left: 2rem !important; 68 | padding-right: 1.5rem !important; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Shared/NavMenu.razor: -------------------------------------------------------------------------------- 1 |  7 | 8 |
9 | 31 |
32 | 33 | @code { 34 | private bool collapseNavMenu = true; 35 | 36 | private string NavMenuCssClass => collapseNavMenu ? "collapse" : null; 37 | 38 | private void ToggleNavMenu() 39 | { 40 | collapseNavMenu = !collapseNavMenu; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/Shared/NavMenu.razor.css: -------------------------------------------------------------------------------- 1 | .navbar-toggler { 2 | background-color: rgba(255, 255, 255, 0.1); 3 | } 4 | 5 | .top-row { 6 | height: 3.5rem; 7 | background-color: rgba(0,0,0,0.4); 8 | } 9 | 10 | .navbar-brand { 11 | font-size: 1.1rem; 12 | } 13 | 14 | .oi { 15 | width: 2rem; 16 | font-size: 1.1rem; 17 | vertical-align: text-top; 18 | top: -2px; 19 | } 20 | 21 | .nav-item { 22 | font-size: 0.9rem; 23 | padding-bottom: 0.5rem; 24 | } 25 | 26 | .nav-item:first-of-type { 27 | padding-top: 1rem; 28 | } 29 | 30 | .nav-item:last-of-type { 31 | padding-bottom: 1rem; 32 | } 33 | 34 | .nav-item ::deep a { 35 | color: #d7d7d7; 36 | border-radius: 4px; 37 | height: 3rem; 38 | display: flex; 39 | align-items: center; 40 | line-height: 3rem; 41 | } 42 | 43 | .nav-item ::deep a.active { 44 | background-color: rgba(255,255,255,0.25); 45 | color: white; 46 | } 47 | 48 | .nav-item ::deep a:hover { 49 | background-color: rgba(255,255,255,0.1); 50 | color: white; 51 | } 52 | 53 | @media (min-width: 641px) { 54 | .navbar-toggler { 55 | display: none; 56 | } 57 | 58 | .collapse { 59 | /* Never collapse the sidebar for wide screens */ 60 | display: block; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/TwoWeeksReady.Admin.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net6.0 5 | 4c82d094-3afe-4274-922b-9c0d8bdda7c5 6 | enable 7 | 8 | 9 | 10 | 11 | Always 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | %(ClientImages.Identity) 37 | $([MSBuild]::Add($(ClientImage.IndexOf(`2wr-app`)), 14)) 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/_Imports.razor: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using Microsoft.AspNetCore.Authorization 3 | @using Microsoft.AspNetCore.Components.Authorization 4 | @using Microsoft.AspNetCore.Components.Forms 5 | @using Microsoft.AspNetCore.Components.Routing 6 | @using Microsoft.AspNetCore.Components.Web 7 | @using Microsoft.AspNetCore.Components.Web.Virtualization 8 | @using Microsoft.JSInterop 9 | @using TwoWeeksReady.Admin 10 | @using TwoWeeksReady.Admin.Data 11 | @using TwoWeeksReady.Admin.Shared 12 | @using TwoWeeksReady.Common 13 | @using TwoWeeksReady.Common.EmergencyKits 14 | @using TwoWeeksReady.Admin.Components -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "DetailedErrors": true, 3 | "Logging": { 4 | "LogLevel": { 5 | "Default": "Information", 6 | "Microsoft": "Warning", 7 | "Microsoft.Hosting.Lifetime": "Information" 8 | } 9 | }, 10 | "AllowedHosts": "*" 11 | } 12 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft": "Warning", 6 | "Microsoft.Hosting.Lifetime": "Information" 7 | } 8 | }, 9 | "AllowedHosts": "*", 10 | "TinyMCEApiKey": "your-api-key", 11 | "ApiUrl": "http://localhost:7071/api/", 12 | "2wrAppUrl": "http://localhost:8080/", 13 | "Auth0": { 14 | "Domain": "YOUR_AUTH0_DOMAIN", 15 | "ClientId": "YOUR_CLIENT_ID", 16 | "ClientSecret": "YOUR_CLIENT_SECRET" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/wwwroot/css/open-iconic/ICON-LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Waybury 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/wwwroot/css/open-iconic/font/fonts/open-iconic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/admin/TwoWeeksReady.Admin/wwwroot/css/open-iconic/font/fonts/open-iconic.eot -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/wwwroot/css/open-iconic/font/fonts/open-iconic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/admin/TwoWeeksReady.Admin/wwwroot/css/open-iconic/font/fonts/open-iconic.otf -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/admin/TwoWeeksReady.Admin/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/wwwroot/css/open-iconic/font/fonts/open-iconic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/admin/TwoWeeksReady.Admin/wwwroot/css/open-iconic/font/fonts/open-iconic.woff -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | @import url('open-iconic/font/css/open-iconic-bootstrap.min.css'); 2 | 3 | html, body { 4 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; 5 | } 6 | 7 | a, .btn-link { 8 | color: #0366d6; 9 | } 10 | 11 | .btn-primary { 12 | color: #fff; 13 | background-color: #1b6ec2; 14 | border-color: #1861ac; 15 | } 16 | 17 | .content { 18 | padding-top: 1.1rem; 19 | } 20 | 21 | .valid.modified:not([type=checkbox]) { 22 | outline: 1px solid #26b050; 23 | } 24 | 25 | .invalid { 26 | outline: 1px solid red; 27 | } 28 | 29 | .validation-message { 30 | color: red; 31 | } 32 | 33 | #blazor-error-ui { 34 | background: lightyellow; 35 | bottom: 0; 36 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); 37 | display: none; 38 | left: 0; 39 | padding: 0.6rem 1.25rem 0.7rem 1.25rem; 40 | position: fixed; 41 | width: 100%; 42 | z-index: 1000; 43 | } 44 | 45 | #blazor-error-ui .dismiss { 46 | cursor: pointer; 47 | position: absolute; 48 | right: 0.75rem; 49 | top: 0.5rem; 50 | } 51 | 52 | 53 | /** 54 | Required Material Design Configuration 55 | */ 56 | 57 | .mdi::before { 58 | font-size: 24px; 59 | line-height: 14px; 60 | } 61 | 62 | .btn .mdi::before { 63 | position: relative; 64 | top: 4px; 65 | } 66 | 67 | .btn-xs .mdi::before { 68 | font-size: 18px; 69 | top: 3px; 70 | } 71 | 72 | .btn-sm .mdi::before { 73 | font-size: 18px; 74 | top: 3px; 75 | } 76 | 77 | .dropdown-menu .mdi { 78 | width: 18px; 79 | } 80 | 81 | .dropdown-menu .mdi::before { 82 | position: relative; 83 | top: 4px; 84 | left: -8px; 85 | } 86 | 87 | .nav .mdi::before { 88 | position: relative; 89 | top: 4px; 90 | } 91 | 92 | .navbar .navbar-toggle .mdi::before { 93 | position: relative; 94 | top: 4px; 95 | color: #FFF; 96 | } 97 | 98 | .breadcrumb .mdi::before { 99 | position: relative; 100 | top: 4px; 101 | } 102 | 103 | .breadcrumb a:hover { 104 | text-decoration: none; 105 | } 106 | 107 | .breadcrumb a:hover span { 108 | text-decoration: underline; 109 | } 110 | 111 | .alert .mdi::before { 112 | position: relative; 113 | top: 4px; 114 | margin-right: 2px; 115 | } 116 | 117 | .input-group-addon .mdi::before { 118 | position: relative; 119 | top: 3px; 120 | } 121 | 122 | .navbar-brand .mdi::before { 123 | position: relative; 124 | top: 2px; 125 | margin-right: 2px; 126 | } 127 | 128 | .list-group-item .mdi::before { 129 | position: relative; 130 | top: 3px; 131 | left: -3px 132 | } 133 | /** End Required Material Design Configuration */ -------------------------------------------------------------------------------- /admin/TwoWeeksReady.Admin/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/admin/TwoWeeksReady.Admin/wwwroot/favicon.ico -------------------------------------------------------------------------------- /api/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-azuretools.vscode-azurefunctions", 4 | "ms-dotnettools.csharp" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /api/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to .NET Functions", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "processId": "${command:azureFunctions.pickProcess}" 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /api/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "azureFunctions.deploySubpath": "TwoWeeksReady/bin/Release/netcoreapp3.1/publish", 3 | "azureFunctions.projectLanguage": "C#", 4 | "azureFunctions.projectRuntime": "~3", 5 | "debug.internalConsoleOptions": "neverOpen", 6 | "azureFunctions.preDeployTask": "publish" 7 | } -------------------------------------------------------------------------------- /api/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "clean", 6 | "command": "dotnet", 7 | "args": [ 8 | "clean", 9 | "/property:GenerateFullPaths=true", 10 | "/consoleloggerparameters:NoSummary" 11 | ], 12 | "type": "process", 13 | "problemMatcher": "$msCompile", 14 | "options": { 15 | "cwd": "${workspaceFolder}/TwoWeeksReady" 16 | } 17 | }, 18 | { 19 | "label": "build", 20 | "command": "dotnet", 21 | "args": [ 22 | "build", 23 | "/property:GenerateFullPaths=true", 24 | "/consoleloggerparameters:NoSummary" 25 | ], 26 | "type": "process", 27 | "dependsOn": "clean", 28 | "group": { 29 | "kind": "build", 30 | "isDefault": true 31 | }, 32 | "problemMatcher": "$msCompile", 33 | "options": { 34 | "cwd": "${workspaceFolder}/TwoWeeksReady" 35 | } 36 | }, 37 | { 38 | "label": "clean release", 39 | "command": "dotnet", 40 | "args": [ 41 | "clean", 42 | "--configuration", 43 | "Release", 44 | "/property:GenerateFullPaths=true", 45 | "/consoleloggerparameters:NoSummary" 46 | ], 47 | "type": "process", 48 | "problemMatcher": "$msCompile", 49 | "options": { 50 | "cwd": "${workspaceFolder}/TwoWeeksReady" 51 | } 52 | }, 53 | { 54 | "label": "publish", 55 | "command": "dotnet", 56 | "args": [ 57 | "publish", 58 | "--configuration", 59 | "Release", 60 | "/property:GenerateFullPaths=true", 61 | "/consoleloggerparameters:NoSummary" 62 | ], 63 | "type": "process", 64 | "dependsOn": "clean release", 65 | "problemMatcher": "$msCompile", 66 | "options": { 67 | "cwd": "${workspaceFolder}/TwoWeeksReady" 68 | } 69 | }, 70 | { 71 | "type": "func", 72 | "dependsOn": "build", 73 | "options": { 74 | "cwd": "${workspaceFolder}/TwoWeeksReady/bin/Debug/net6.0" 75 | }, 76 | "command": "host start", 77 | "isBackground": true, 78 | "problemMatcher": "$func-dotnet-watch" 79 | } 80 | ] 81 | } -------------------------------------------------------------------------------- /api/TwoWeeksReady/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-azuretools.vscode-azurefunctions", 4 | "ms-dotnettools.csharp" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /api/TwoWeeksReady/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Attach to .NET Functions", 9 | "type": "coreclr", 10 | "request": "attach", 11 | "processId": "${command:azureFunctions.pickProcess}" 12 | } 13 | ] 14 | } -------------------------------------------------------------------------------- /api/TwoWeeksReady/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "azureFunctions.deploySubpath": "bin/Release/netcoreapp3.1/publish", 3 | "azureFunctions.projectLanguage": "C#", 4 | "azureFunctions.projectRuntime": "~3", 5 | "debug.internalConsoleOptions": "neverOpen", 6 | "azureFunctions.preDeployTask": "publish" 7 | } -------------------------------------------------------------------------------- /api/TwoWeeksReady/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "clean", 6 | "command": "dotnet", 7 | "args": [ 8 | "clean", 9 | "/property:GenerateFullPaths=true", 10 | "/consoleloggerparameters:NoSummary" 11 | ], 12 | "type": "process", 13 | "problemMatcher": "$msCompile" 14 | }, 15 | { 16 | "label": "build", 17 | "command": "dotnet", 18 | "args": [ 19 | "build", 20 | "/property:GenerateFullPaths=true", 21 | "/consoleloggerparameters:NoSummary" 22 | ], 23 | "type": "process", 24 | "dependsOn": "clean", 25 | "group": { 26 | "kind": "build", 27 | "isDefault": true 28 | }, 29 | "problemMatcher": "$msCompile" 30 | }, 31 | { 32 | "label": "clean release", 33 | "command": "dotnet", 34 | "args": [ 35 | "clean", 36 | "--configuration", 37 | "Release", 38 | "/property:GenerateFullPaths=true", 39 | "/consoleloggerparameters:NoSummary" 40 | ], 41 | "type": "process", 42 | "problemMatcher": "$msCompile" 43 | }, 44 | { 45 | "label": "publish", 46 | "command": "dotnet", 47 | "args": [ 48 | "publish", 49 | "--configuration", 50 | "Release", 51 | "/property:GenerateFullPaths=true", 52 | "/consoleloggerparameters:NoSummary" 53 | ], 54 | "type": "process", 55 | "dependsOn": "clean release", 56 | "problemMatcher": "$msCompile" 57 | }, 58 | { 59 | "type": "func", 60 | "dependsOn": "build", 61 | "options": { 62 | "cwd": "${workspaceFolder}/bin/Debug/netcoreapp3.1" 63 | }, 64 | "command": "host start", 65 | "isBackground": true, 66 | "problemMatcher": "$func-watch" 67 | } 68 | ] 69 | } -------------------------------------------------------------------------------- /api/TwoWeeksReady/Authorization/AuthorizationExtensions.cs: -------------------------------------------------------------------------------- 1 | using AzureFunctions.OidcAuthentication; 2 | using System.Linq; 3 | 4 | namespace TwoWeeksReady.Authorization 5 | { 6 | public static class AuthorizationExtensions 7 | { 8 | public static bool IsInRole(this ApiAuthenticationResult authenticationResult, string roleName) 9 | { 10 | var roles = authenticationResult.User.FindAll("https://schemas.2wradmin.com/role"); 11 | return roles.Any(r => r.Value == roleName); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /api/TwoWeeksReady/Authorization/Roles.cs: -------------------------------------------------------------------------------- 1 | namespace TwoWeeksReady.Authorization 2 | { 3 | public static class Roles 4 | { 5 | public static string Admin = "admin"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /api/TwoWeeksReady/Common/BaseFunction.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http; 2 | using System.Security.Claims; 3 | using System.Threading.Tasks; 4 | using AzureFunctions.OidcAuthentication; 5 | using Microsoft.AspNetCore.Http; 6 | using Microsoft.Azure.Documents.Client; 7 | using Microsoft.Extensions.Logging; 8 | 9 | namespace TwoWeeksReady.Common 10 | { 11 | public abstract class BaseFunction 12 | { 13 | protected const string DefaultDatabaseName = "2wr"; 14 | protected const string DefaultDbConnectionName = "CosmosDbConnection"; 15 | 16 | protected BaseFunction(IApiAuthentication apiAuthentication) 17 | { 18 | ApiAuthentication = apiAuthentication; 19 | } 20 | 21 | protected IApiAuthentication ApiAuthentication 22 | { 23 | get; 24 | private set; 25 | } 26 | protected ClaimsPrincipal Principal 27 | { 28 | get; 29 | private set; 30 | } 31 | 32 | protected async Task Authorized(HttpRequest req, ILogger log) 33 | { 34 | var authorizationResult = await ApiAuthentication.AuthenticateAsync(req.Headers); 35 | if (authorizationResult.Failed) 36 | { 37 | log.LogWarning(authorizationResult.FailureReason); 38 | return false; 39 | } 40 | 41 | Principal = authorizationResult.User; 42 | return true; 43 | } 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /api/TwoWeeksReady/EmergencyKits/CreateKitFromBaseRequest.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | 3 | namespace TwoWeeksReady.EmergencyKits 4 | { 5 | public class CreateKitFromBaseRequest 6 | { 7 | [JsonProperty(PropertyName = "baseKitId")] 8 | public string BaseKitId {get; set;} 9 | 10 | [JsonProperty(PropertyName="name")] 11 | public string Name {get;set;} 12 | 13 | [JsonProperty(PropertyName = "count")] 14 | public int Count {get;set;} 15 | } 16 | } -------------------------------------------------------------------------------- /api/TwoWeeksReady/FamilyMembers/FamilyMembersApi.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Http; 6 | using Microsoft.AspNetCore.Mvc; 7 | using Microsoft.Azure.Documents.Client; 8 | using Microsoft.Azure.Documents.Linq; 9 | using Microsoft.Azure.WebJobs; 10 | using Microsoft.Azure.WebJobs.Extensions.Http; 11 | using Microsoft.Azure.WebJobs.Host; 12 | using Microsoft.Extensions.Logging; 13 | using TwoWeeksReady.Common.FamilyMembers; 14 | 15 | namespace TwoWeeksReady.FamilyMembers 16 | { 17 | public class FamilyMembersApi 18 | { 19 | 20 | [FunctionName("familymembers")] 21 | public async Task GetList( 22 | [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] 23 | HttpRequest req, 24 | [CosmosDB( databaseName: "2wr", collectionName: "familymembers", ConnectionStringSetting = "CosmosDBConnection")] 25 | DocumentClient client, 26 | ILogger log) 27 | { 28 | log.LogInformation($"Getting list of family members"); 29 | 30 | Uri collectionUri = UriFactory.CreateDocumentCollectionUri("2wr", "familymembers"); 31 | 32 | var query = client.CreateDocumentQuery(collectionUri).AsDocumentQuery(); 33 | var familyMembers = new List(); 34 | while (query.HasMoreResults) 35 | { 36 | var result = await query.ExecuteNextAsync(); 37 | familyMembers.AddRange(result); 38 | 39 | } 40 | 41 | return new OkObjectResult(familyMembers); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /api/TwoWeeksReady/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Azure.Functions.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using AzureFunctions.OidcAuthentication; 4 | 5 | [assembly: FunctionsStartup(typeof(TwoWeeksReady.Startup))] 6 | 7 | namespace TwoWeeksReady 8 | { 9 | public class Startup : FunctionsStartup 10 | { 11 | public override void Configure(IFunctionsHostBuilder builder) 12 | { 13 | builder.Services.AddOidcApiAuthorization(); 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /api/TwoWeeksReady/TwoWeeksReady.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net6.0 4 | v4 5 | <_FunctionsSkipCleanOutput>true 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | PreserveNewest 26 | 27 | 28 | PreserveNewest 29 | Never 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /api/TwoWeeksReady/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "logging": { 4 | "applicationInsights": { 5 | "samplingExcludedTypes": "Request", 6 | "samplingSettings": { 7 | "isEnabled": true 8 | } 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /api/api.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "path": "." 5 | }, 6 | { 7 | "path": "..\\TwoWeeksReady.Common" 8 | } 9 | ], 10 | "settings": { 11 | "debug.internalConsoleOptions": "neverOpen" 12 | } 13 | } -------------------------------------------------------------------------------- /api/api.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.31205.134 5 | MinimumVisualStudioVersion = 15.0.26124.0 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TwoWeeksReady", "TwoWeeksReady\TwoWeeksReady.csproj", "{917B6C53-4118-4DC9-A04A-448AC3F35452}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TwoWeeksReady.Common", "..\TwoWeeksReady.Common\TwoWeeksReady.Common.csproj", "{ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Debug|x64 = Debug|x64 14 | Debug|x86 = Debug|x86 15 | Release|Any CPU = Release|Any CPU 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Debug|x64.ActiveCfg = Debug|Any CPU 23 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Debug|x64.Build.0 = Debug|Any CPU 24 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Debug|x86.ActiveCfg = Debug|Any CPU 25 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Debug|x86.Build.0 = Debug|Any CPU 26 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Release|Any CPU.Build.0 = Release|Any CPU 28 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Release|x64.ActiveCfg = Release|Any CPU 29 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Release|x64.Build.0 = Release|Any CPU 30 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Release|x86.ActiveCfg = Release|Any CPU 31 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Release|x86.Build.0 = Release|Any CPU 32 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 33 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Debug|Any CPU.Build.0 = Debug|Any CPU 34 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Debug|x64.ActiveCfg = Debug|Any CPU 35 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Debug|x64.Build.0 = Debug|Any CPU 36 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Debug|x86.ActiveCfg = Debug|Any CPU 37 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Debug|x86.Build.0 = Debug|Any CPU 38 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Release|x64.ActiveCfg = Release|Any CPU 41 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Release|x64.Build.0 = Release|Any CPU 42 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Release|x86.ActiveCfg = Release|Any CPU 43 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Release|x86.Build.0 = Release|Any CPU 44 | EndGlobalSection 45 | GlobalSection(SolutionProperties) = preSolution 46 | HideSolutionNode = FALSE 47 | EndGlobalSection 48 | GlobalSection(ExtensibilityGlobals) = postSolution 49 | SolutionGuid = {D66B7A36-58A8-47DB-A7B5-23FDA5880877} 50 | EndGlobalSection 51 | EndGlobal 52 | -------------------------------------------------------------------------------- /assets/icons/app/2 Weeks Ready Icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/app/2 Weeks Ready Icon-128.png -------------------------------------------------------------------------------- /assets/icons/app/2 Weeks Ready Icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/app/2 Weeks Ready Icon-16.png -------------------------------------------------------------------------------- /assets/icons/app/2 Weeks Ready Icon-256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/app/2 Weeks Ready Icon-256.png -------------------------------------------------------------------------------- /assets/icons/app/2 Weeks Ready Icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/app/2 Weeks Ready Icon-32.png -------------------------------------------------------------------------------- /assets/icons/app/2 Weeks Ready Icon-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/app/2 Weeks Ready Icon-512.png -------------------------------------------------------------------------------- /assets/icons/app/2 Weeks Ready Icon-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/app/2 Weeks Ready Icon-64.png -------------------------------------------------------------------------------- /assets/icons/kits/2WR Kit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/2WR Kit.png -------------------------------------------------------------------------------- /assets/icons/kits/Child Kit128-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Child Kit128-.png -------------------------------------------------------------------------------- /assets/icons/kits/Child Kit16-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Child Kit16-.png -------------------------------------------------------------------------------- /assets/icons/kits/Child Kit256-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Child Kit256-.png -------------------------------------------------------------------------------- /assets/icons/kits/Child Kit32-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Child Kit32-.png -------------------------------------------------------------------------------- /assets/icons/kits/Child Kit512-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Child Kit512-.png -------------------------------------------------------------------------------- /assets/icons/kits/Child Kit64-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Child Kit64-.png -------------------------------------------------------------------------------- /assets/icons/kits/Miscellaneous Icons V3.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Miscellaneous Icons V3.ai -------------------------------------------------------------------------------- /assets/icons/kits/Pet Kit128-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Pet Kit128-.png -------------------------------------------------------------------------------- /assets/icons/kits/Pet Kit16-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Pet Kit16-.png -------------------------------------------------------------------------------- /assets/icons/kits/Pet Kit256-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Pet Kit256-.png -------------------------------------------------------------------------------- /assets/icons/kits/Pet Kit32-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Pet Kit32-.png -------------------------------------------------------------------------------- /assets/icons/kits/Pet Kit512-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Pet Kit512-.png -------------------------------------------------------------------------------- /assets/icons/kits/Pet Kit64-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Pet Kit64-.png -------------------------------------------------------------------------------- /assets/icons/kits/Vehicle Kit128-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Vehicle Kit128-.png -------------------------------------------------------------------------------- /assets/icons/kits/Vehicle Kit16-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Vehicle Kit16-.png -------------------------------------------------------------------------------- /assets/icons/kits/Vehicle Kit256-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Vehicle Kit256-.png -------------------------------------------------------------------------------- /assets/icons/kits/Vehicle Kit32-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Vehicle Kit32-.png -------------------------------------------------------------------------------- /assets/icons/kits/Vehicle Kit512-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Vehicle Kit512-.png -------------------------------------------------------------------------------- /assets/icons/kits/Vehicle Kit64-.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Vehicle Kit64-.png -------------------------------------------------------------------------------- /assets/images/210909_2WR_EMAIL GRAPHIC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/210909_2WR_EMAIL GRAPHIC.png -------------------------------------------------------------------------------- /assets/images/Build A Kit/Child Kit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Build A Kit/Child Kit.png -------------------------------------------------------------------------------- /assets/images/Build A Kit/Home Kit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Build A Kit/Home Kit.png -------------------------------------------------------------------------------- /assets/images/Build A Kit/Pet Kit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Build A Kit/Pet Kit.png -------------------------------------------------------------------------------- /assets/images/Build A Kit/Vehicle Kit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Build A Kit/Vehicle Kit.png -------------------------------------------------------------------------------- /assets/images/Build A Kit/Work Kit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Build A Kit/Work Kit.png -------------------------------------------------------------------------------- /assets/images/Hazard Information/Earthquake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Hazard Information/Earthquake.png -------------------------------------------------------------------------------- /assets/images/Hazard Information/Flood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Hazard Information/Flood.png -------------------------------------------------------------------------------- /assets/images/Hazard Information/Landslide.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Hazard Information/Landslide.png -------------------------------------------------------------------------------- /assets/images/Hazard Information/Power Outage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Hazard Information/Power Outage.png -------------------------------------------------------------------------------- /assets/images/Hazard Information/Public Health Emergency.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Hazard Information/Public Health Emergency.png -------------------------------------------------------------------------------- /assets/images/Hazard Information/Radiological.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Hazard Information/Radiological.png -------------------------------------------------------------------------------- /assets/images/Hazard Information/Severe Weather.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Hazard Information/Severe Weather.png -------------------------------------------------------------------------------- /assets/images/Hazard Information/Tsunami.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Hazard Information/Tsunami.png -------------------------------------------------------------------------------- /assets/images/Hazard Information/Volcano.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Hazard Information/Volcano.png -------------------------------------------------------------------------------- /assets/images/Hazard Information/Wildfire.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Hazard Information/Wildfire.png -------------------------------------------------------------------------------- /assets/images/codetour_api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/codetour_api.png -------------------------------------------------------------------------------- /assets/images/codetour_ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/codetour_ui.png -------------------------------------------------------------------------------- /assets/images/forestfire_resized.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/forestfire_resized.jpg -------------------------------------------------------------------------------- /assets/images/seismograph_resized.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/seismograph_resized.jpg -------------------------------------------------------------------------------- /assets/images/twoweeksready.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/twoweeksready.png -------------------------------------------------------------------------------- /assets/models/EmergencyKits.drawio: -------------------------------------------------------------------------------- 1 | 7Vxbd9o4EP41nLP7kB5fMJDHQC5Nm+6mTdPu2ZceYcugIluuLELor9+RLNsYOQkk3JL1OSTg0cXSfN9IM2NByx1E9xccJeNPLMC05VjBfcs9bTmO7bR78CYl80zStTqZYMRJoCuVghvyG2uhpaVTEuC0UlEwRgVJqkKfxTH2RUWGOGezarWQ0epdEzTChuDGR9SUfieBGGfSntMt5e8xGY3zO9ud46wkQnllPZN0jAI2WxC5Zy13wBkT2afofoCpVF6ul++X8+/0atK5+PA5/YVu+x+//vXtKOvsfJ0mxRQ4jsWzu/49Cc/ff2v//Ce5Pv88sy5Ohh+OdBPrDtGp1lcfpfjHRyL0nMU8V2Q6IxFFMVz1QxaLG10CaugjSkYxfPZhfJiD4A5zQQCDE10gWAJSf0xocIXmbCpnkQrkT/Kr/phx8hu6RRSKbBBAMReaTk6nUuNGtgSxBVKOU6hznavGLkRXKBW6js8oRUlKhmrAskqE+IjEfSYEi/KO2DQOcKCvCqzVheBsUrBHtg8JpQNGGVeqcQOEe6Ff1Fwo6fg9PAyhZEUINdRSf/h+gcAa0gvMIiz4HKrc5+aYtdDWabf19azkut3RsnGF51qItH2Niq6Lu30Be0TxCLRW3M5xn3k/p1O9HaLAlBgJ3Jd6TxeZCx8WZlqKFJ/X4LZtclsS+zIwqA26Fgs0pjgUD5I4TZBP4tGVqnPaLiVf9GSliEHbkCoCjUkQ4FgRTCCBMg5KViWMxEJpw+vDC3Q2sN55LQ8GNIBru7yGl6zOxYDFwDBEFIUwEHyGJclryPWosT9NrnkVtHXBXeRSBdV1IXQMCP9CEX5z+D2y9oxFRPXHbaHsObtD+ao/Op//8DpeNwjjbz//HV3bfx95BsqX4A00KG8U5W5vz7bcMVBuvIzX4mUcV3d9z17Vy+g8y8uwl7wMt3e4Xka3jtb/Xx+jszK1DsXH6BkA3qaYv0EEN7r/rI3z3r2MduNLbh/lXXoZtSibXka2TzYwbxJm22rvGWfbNOcmaNg8zu4zHa+N7c62W+tfCRw1ocNGQ4dce+cLLWOmtLmtqMLNd4t1w4oi67leWOG2VwgrujsPK2rXt/qwAmj/Bh3TFVevYik4yNiifpcyc9BNcLENpPceXeRLVxNebBXnvccXxwbMpzj1OUkEabzPTaO9/zDDTA6d3SeEz09h82/Q3jDauww26hdx83nj5ymKBRHzBuwNg+3t2zdzTBc7B/s2rnky1QD+MsB7e3fRzFTC9ZgJ1iC94ajL2reT5phIX6Ynd4hQqfDLuO7BcwP6y0B3d+iq1Y/ZXM/zs4xNuvDVnDRwvWpOcPUDjcfPygl63is60GhGI/0fTVqwuzLHDuXIgW1mEZpk0eZx3mVSsP74qpkUbLJFW4N77yccHTPb3wQYWwB6p2nBeqQfThRdYz4A9TQBxqZB33t28GHMm3zRFvDeZYKw3sjNs2QGyDgOTuSXFOGKJQqRJyKtqlahuTxvoctwMMJ5GIrpkM3OSkFfCaAgJ9DaMVjKptzHj8xX6xbi1BFeBUs53EeR1DhLwi2GWG09II4pEuRusY9Ho7drye3Wg19Fc/Lsfd5FNmHdquSC0ZF7/ERHmUae7uho+XzJUj8sDFNc6WJTkWFNLjtHveSqyiMsrBVPrExDnU3oUzTEtI/8yUiRd+lwkMqdZGkN21l9QciNS3/tVw+rVXzZdvWMwdEL6ZSzcmdYmVH8JxSbD5gegotnS9+rxWsz1p8fkNoievUPEUz0XvOmsO81fCn75i0n8VZew5ePEi53dFBreD2zzKTQ4azhj9rCm17D60MBM7FzWGv4lvF63Wt4TZ6m5XSoemwDRZ2R/CSfHUGdswjDwhH7cvLqsWFWD+5bVs2FSS645vgoREMO0ApY1h1rQiAoA9d6jIR6kz0D7P4U9Ce/nGJNU6wqMIkjtE5YIstkPQR/MZ5llXjW2Tt4u82uZkRNOMVU/nqKY4UcCJS1oiSVEhbCv2E2HT0QFMtRkThQIyyGFE+joepUltyRYIpoWTvBIpX3lYqR1zKBCe1IKkPL2knpofkcL89kIjUJ5bAD5i2JwFGqbl2IyjHD/2gqfzOGziEoLir8Kg7nWMO5IrZKvFhpgn0SEjXMP1RJgnmqBqwGpkXizwU4kxLN+kBeB7228VgsN0rz4LwO4kHglVdfZcR/KpcQtz8bw7RvQC5vNeMoeTDMX3QQ1tviV7fqztLWZyZcvF5NAG471sOW/7KMi5lyMQ31WRY6mKZC2Yk2iACHJFZ8UdxA2tok379mxJYkJhmFwoL4mpvanFRPOY+Bi1T1J1tHKAZbygxFMRAGjLleHIa5QYVhvR1l3aOKRbxrqLtI3V6Vum1ni9yFy/JHn7I9qfzpLPfsPw== -------------------------------------------------------------------------------- /assets/models/EmergencyKits.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/models/EmergencyKits.png -------------------------------------------------------------------------------- /assets/models/HazardHuntHazardInformation.drawio: -------------------------------------------------------------------------------- 1 | 7Vnbdto4FP0aHunCNubyGCCBtEyHhjSZ6UuXsGVbQZZcWQ6Qr++RLF+IaUoy6WQurMUy0taxztHZW0ISLWccb6cCJdFv3Me0ZXf8bcuZtGzbGthD+FLIziAdp5sjoSC+wSpgSR5wYWjQjPg43TOUnFNJkn3Q44xhT+5hSAi+2TcLON33mqAQN4Clh2gTvSW+jHJ0YPcrfIZJGBWerZ4ZcYwKYzOSNEI+39Qg57zljAXnMi/F2zGmKntFXm4vd7d0vu5N339Kv6HPow/XH2/aeWcXz3mlHILATL6464d1cDG76d79kSwuPm0607PV+3a7l3d9j2hm8jVDD0j4lyzgLedshFL8lahyngG5K9KabkhMEYPaKOBMLk0LJGWEKAkZlD2IFgsA7rGQBBg5Mw2SJ4B6EaH+HO14psaUSuSti9oo4oI8QLeIQpMFADQLacRl9/YslupNgDuACpyCzaJIlFVCc5RKY+NxSlGSkpUOWJnESISEjbiUPC464hnzsW9qJfO6IgVfl1pS7weE0jGnXOjUOD7Cg8ArLWstPW+AVwG0HEmoIV7lD29rcjYETzGPsRQ7MDGtjmO0amar7Zr6ppK+1TNYVJN9YYfMbAvLrktvVzA7EQsha6U765E7Z3CkO7u37w5RUApDEo9U3tO6jqFQG2kFaXU/Q+lWvyF1re7Lk7r/Leoe7qutVNbP1GYNX6Ru133kr/sPVvegoe5LvyFryLOsSZjiQP5QwGmCPMLCubaZdCvkygxUQRzeDagWT0R8HzMtLokkyvWnFJVwwqTOhDuCD+Rr3HnntlwIaAx1q6rDR5kLOeYM1IWIlg8GcW+wEvgBYT091X+urN0+Y89lti6kPUqfzd+wwd9HFOP/HINPrDyRjKkp/jKeXfuNeS72kjWeJzj1BEkk4exE9+vS3R+8Nd1Wg+5FxGVzw3Ei+i8RbXW6b8203ZzYRMCmgtyfVvHXZtt54UbsJWzPR+HF7qvbc/t+wG7uvoQL6/d2k+zzrd7j0Tlh6xPfr8y3+zduzw7z3VzHW3aP6sMcNPVCVVLHSbBRB0oRo/z3PLcBn5VZASYFsMTiHqd52PDQl1yQb9MDVAQ8BUZ+mzOq0gJNyiqBw586hPr6Sk09IuU/S7F4B9/XEVH96UfeR3618zjEsXLK/Hr7LAMG7U7M/YzqyGSEFOBlQpGrgxD4WwYLnM4cYErIyhFGMoO4VACTPMzc94oDc/UuQUU67yus5woXehwpBv3ASUm7IKwclBmytstDznSyV3nOPYrSNM+hHglhERZEhRwIOPXqXuKiR4/76p22hnV6Nmh3KMQIqbXbRIBWhBK5K3KN7znVrZq0ImzVALmQRGegJD+puD+8MphZZDWO1YznlxC1M7iBzKoAgFvVrtUSMlG7TGe0iYjES8CVq41AyQ/Xjfrkbk7i1zm7Dx6dpZsruDs4dHS3nzi6Hzulg7v5bGrZ/e7Zh8/bxfDLn9fdq3ZzRufy19o3N5+nu6FfdDfU0M2xkjv65tPq/w9uPqFa/f2Qm1f/4jjn3wE= -------------------------------------------------------------------------------- /assets/models/HazardHuntHazardInformation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/models/HazardHuntHazardInformation.png -------------------------------------------------------------------------------- /assets/wiki/Family plan page 1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/Family plan page 1.PNG -------------------------------------------------------------------------------- /assets/wiki/Family plan page 2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/Family plan page 2.PNG -------------------------------------------------------------------------------- /assets/wiki/Family plan page 3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/Family plan page 3.PNG -------------------------------------------------------------------------------- /assets/wiki/Family plan page 4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/Family plan page 4.PNG -------------------------------------------------------------------------------- /assets/wiki/Family plan page 5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/Family plan page 5.PNG -------------------------------------------------------------------------------- /assets/wiki/Family plan page 6.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/Family plan page 6.PNG -------------------------------------------------------------------------------- /assets/wiki/Family plan page 7.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/Family plan page 7.PNG -------------------------------------------------------------------------------- /assets/wiki/Family plan page 8.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/Family plan page 8.PNG -------------------------------------------------------------------------------- /assets/wiki/HazardHuntDetails.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/HazardHuntDetails.png -------------------------------------------------------------------------------- /assets/wiki/HazardHuntEntry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/HazardHuntEntry.png -------------------------------------------------------------------------------- /assets/wiki/HazardHuntListing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/HazardHuntListing.png -------------------------------------------------------------------------------- /az/create-admin-app-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | RESOURCE_GROUP='2wr-resources' 5 | ENV_PREFIX='2wrdev' 6 | LOCATION='centralus' 7 | 8 | while getopts :r:e: opt; do 9 | case ${opt} in 10 | r) RESOURCE_GROUP=${OPTARG};; 11 | e) ENV_PREFIX=${OPTARG};; 12 | l) LOCATION=${OPTARG};; 13 | esac 14 | done 15 | 16 | az configure -d group=$RESOURCE_GROUP 17 | az configure -d location=$LOCATION 18 | az group create -n $RESOURCE_GROUP 19 | 20 | echo "Create Web apps" 21 | APPSERVICEPLAN_NAME=${ENV_PREFIX}admin_asp 22 | WEBAPP_NAME=${ENV_PREFIX}admin 23 | az appservice plan create --sku B1 --name $APPSERVICEPLAN_NAME 24 | az webapp create --plan $APPSERVICEPLAN_NAME --name $WEBAPP_NAME --runtime "DOTNET|5.0" 25 | 26 | -------------------------------------------------------------------------------- /az/create-backend-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | RESOURCE_GROUP='2wr-resources' 5 | ENV_PREFIX='2wrdev' 6 | LOCATION='centralus' 7 | 8 | while getopts :r:e: opt; do 9 | case ${opt} in 10 | r) RESOURCE_GROUP=${OPTARG};; 11 | e) ENV_PREFIX=${OPTARG};; 12 | l) LOCATION=${OPTARG};; 13 | esac 14 | done 15 | 16 | az configure -d group=$RESOURCE_GROUP 17 | az configure -d location=$LOCATION 18 | az group create -n $RESOURCE_GROUP 19 | 20 | 21 | STORAGE_ACCOUNT=${ENV_PREFIX}fnstorage 22 | echo "Creating Storage Account ${STORAGE_ACCOUNT}" 23 | az storage account create -n $STORAGE_ACCOUNT 24 | 25 | echo "Create app insights" 26 | az extension add -n application-insights 27 | APP_INSIGHTS=${ENV_PREFIX}ai 28 | az monitor app-insights component create --app $APP_INSIGHTS 29 | 30 | echo "Create function apps" 31 | az functionapp create --consumption-plan-location $LOCATION --name $ENV_PREFIX --os-type Windows --runtime dotnet --storage-account $STORAGE_ACCOUNT --app-insights $APP_INSIGHTS --functions-version 3 32 | CDN_PROFILE_NAME=${ENV_PREFIX} 33 | ALLOWED_ORIGINS="https://${CDN_PROFILE_NAME}.azureedge.net http://localhost:8080" 34 | az functionapp cors remove -n $ENV_PREFIX --allowed-origins $ALLOWED_ORIGINS 35 | az functionapp cors add -n $ENV_PREFIX --allowed-origins $ALLOWED_ORIGINS 36 | 37 | echo "Create Cosmos DB" 38 | az cosmosdb create -n $ENV_PREFIX --enable-free-tier true 39 | az cosmosdb sql database create -a $ENV_PREFIX -n 2wr --throughput 400 40 | az cosmosdb sql container create -a $ENV_PREFIX -d 2wr -n basekits --partition-key-path "/id" 41 | az cosmosdb sql container create -a $ENV_PREFIX -d 2wr -n familymembers --partition-key-path "/id" 42 | az cosmosdb sql container create -a $ENV_PREFIX -d 2wr -n familyplans --partition-key-path "/userid" 43 | az cosmosdb sql container create -a $ENV_PREFIX -d 2wr -n emergencykits --partition-key-path "/userId" 44 | az cosmosdb sql container create -a $ENV_PREFIX -d 2wr -n hazardhunts --partition-key-path "/id" 45 | az cosmosdb sql container create -a $ENV_PREFIX -d 2wr -n hazardinformation --partition-key-path "/id" 46 | 47 | echo "Configure function apps" 48 | CONNECTION_STRING=$(az cosmosdb keys list --type connection-strings -n $ENV_PREFIX --query connectionStrings[0].connectionString --out tsv ) 49 | az webapp config connection-string set -n $ENV_PREFIX --setting CosmosDBConnection="$CONNECTION_STRING" -t "Custom" -------------------------------------------------------------------------------- /az/create-frontend-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | RESOURCE_GROUP='2wr-resources' 5 | ENV_PREFIX='2wrdev' 6 | LOCATION='centralus' 7 | 8 | while getopts :r:e: opt; do 9 | case ${opt} in 10 | r) RESOURCE_GROUP=${OPTARG};; 11 | e) ENV_PREFIX=${OPTARG};; 12 | l) LOCATION=${OPTARG};; 13 | esac 14 | done 15 | 16 | echo "Creating Resource Group $RESOURCE_GROUP in $LOCATION" 17 | 18 | az configure -d group=$RESOURCE_GROUP 19 | az configure -d location=$LOCATION 20 | az group create -n $RESOURCE_GROUP 21 | 22 | STORAGE_ACCOUNT=${ENV_PREFIX}webstorage 23 | echo "Creating static site Storage Account ${STORAGE_ACCOUNT}" 24 | az storage account create -n $STORAGE_ACCOUNT 25 | az storage blob service-properties update --account-name $STORAGE_ACCOUNT --static-website --404-document 404.html --index-document index.html 26 | STORAGE_WEB_ENDPOINT=$(az storage account show -n $STORAGE_ACCOUNT --query primaryEndpoints.web -o tsv | awk -F "/" '{ print $3 }') 27 | 28 | echo "Storage endpoint for static site hosting: $STORAGE_WEB_ENDPOINT" 29 | 30 | CDN_PROFILE_NAME=${ENV_PREFIX} 31 | echo "Creating CDN Profile $CDN_PROFILE_NAME" 32 | az cdn profile create -n $CDN_PROFILE_NAME --sku Standard_Microsoft 33 | az cdn endpoint create -n $CDN_PROFILE_NAME --profile-name $CDN_PROFILE_NAME --origin $STORAGE_WEB_ENDPOINT --origin-host-header $STORAGE_WEB_ENDPOINT --enable-compression 34 | az cdn endpoint rule add -n $CDN_PROFILE_NAME --profile-name $CDN_PROFILE_NAME --rule-name enforcehttps --order 1 --action-name "UrlRedirect" --redirect-type Found --redirect-protocol HTTPS --match-variable RequestScheme --operator Equal --match-value HTTP 35 | az cdn endpoint rule add -n $CDN_PROFILE_NAME --profile-name $CDN_PROFILE_NAME --rule-name sparewrite --order 2 --action-name "UrlRewrite" --source-pattern '/' --destination /index.html --preserve-unmatched-path false --match-variable UrlFileExtension --operator LessThan --match-value 1 36 | 37 | -------------------------------------------------------------------------------- /az/deploy-admin-app.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | RESOURCE_GROUP='2wr-resources' 5 | ENV_PREFIX='2wrdev' 6 | 7 | while getopts :r:e:z: opt; do 8 | case ${opt} in 9 | r) RESOURCE_GROUP=${OPTARG};; 10 | e) ENV_PREFIX=${OPTARG};; 11 | z) ZIP_PACKAGE=${OPTARG};; 12 | esac 13 | done 14 | 15 | az configure -d group=$RESOURCE_GROUP 16 | 17 | echo "Deploying admin app" 18 | WEBAPP_NAME=${ENV_PREFIX}admin 19 | az webapp deployment source config-zip -n $WEBAPP_NAME --src $ZIP_PACKAGE -------------------------------------------------------------------------------- /az/deploy-backend.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | RESOURCE_GROUP='2wr-resources' 5 | ENV_PREFIX='2wrdev' 6 | 7 | while getopts :r:e:z: opt; do 8 | case ${opt} in 9 | r) RESOURCE_GROUP=${OPTARG};; 10 | e) ENV_PREFIX=${OPTARG};; 11 | z) ZIP_PACKAGE=${OPTARG};; 12 | esac 13 | done 14 | 15 | az configure -d group=$RESOURCE_GROUP 16 | 17 | echo "Deploying function app" 18 | az functionapp deployment source config-zip -n $ENV_PREFIX --src $ZIP_PACKAGE -------------------------------------------------------------------------------- /az/deploy-frontend.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | RESOURCE_GROUP='2wr-resources' 5 | ENV_PREFIX='2wrdev' 6 | SOURCE_FOLDER='../2wr-app/dist' 7 | 8 | while getopts :r:e:s: opt; do 9 | case ${opt} in 10 | r) RESOURCE_GROUP=${OPTARG};; 11 | e) ENV_PREFIX=${OPTARG};; 12 | s) SOURCE_FOLDER=${OPTARG};; 13 | esac 14 | done 15 | 16 | az configure -d group=$RESOURCE_GROUP 17 | 18 | STORAGE_ACCOUNT=${ENV_PREFIX}webstorage 19 | echo "Deploying to $STORAGE_ACCOUNT" 20 | az storage blob upload-batch --account-name $STORAGE_ACCOUNT -s $SOURCE_FOLDER -d '$web' 21 | az cdn endpoint purge -n $ENV_PREFIX --profile-name $ENV_PREFIX --no-wait --content-paths '/' '/index.html' '/manifest.json' '/sw.js' -------------------------------------------------------------------------------- /solution architecture.xml: -------------------------------------------------------------------------------- 1 | 7VrbcuI4EP0aqnYf4vId/Agh7FwyVdSmajKzLykFK7YmsuWV5QD5+m3ZEvhGYBKcnYdJKmC1hC6nu093i4ycy2TzF0dZ/IWFmI5sM9yMnPnIti3XcuFNSraVZDxRgoiTUA3aC27IM1ZCU0kLEuK8MVAwRgXJmsIVS1O8Eg0Z4pytm8MeGG2umqEIdwQ3K0S70lsSilhJLdPcd3zAJIrV0hNPdSRID1aCPEYhW9dEztXIueSMieop2VxiKsHTuFSfWxzo3W2M41Sc8oFv11/IPzeZa339YX7/bH16yK7GF+NqlidEC3VgtVmx1QhEnBWZGoa5wJs+3NG9Hm5292XtTgtmglmCBd/CEDXRREOpLMTTCK73eNtaFtegth0lRErH0W7uPQzwoJD4CVTc46isYyLwTYZWsr0G2x85s1gksMzcgkeUZ5U1PpANhqVmBwGsA3VYRV306ujYfejYQ6FjHUenc/waNBkjqSj35M1G3lyCRUmUgmAFQGAOApKUXjl7YKlQlGDZe/mcJBHsnJJ7eEXPBcfyRCECK0Q5kIW9mErh3SXLE5bfzWdG/hQNoQM1i980YKtrv0GPgoKh9OP36MensOqsoA01+f8WknxKmC/yEucpDLCCbLPvhKdIvZdzUPL6OT4g/ox4mOu57vnb91Mawjk3Cb6LofMzEflgayxQQqi0oCVF6XDLXCWYRzhdbU85DwilfWhhy6PBZaQ8F5w94ktGGfjpPGVp6aaE0pao5u99TCl9kECQnSrPT0gYypVmDHoeaBkmY5DhtMUCwRBurFOTE+OO5Q/GrOYvEI6dJpvteKoGizV+V1iCDirT5cc3R+TzmZVl9iNaR8x/V8Qmv2aIXrEkKwSw62JRpCtBWHo3zbL8zeH5kALUNJ7VsOjAcC1r7Ltj05tMbMdzOvbtu11leb6x+4QdwAz+UCRgdXSFQ6hJVJNxEbOIpYhe7aUzIIU0lGqcm5JFd2OuGcuUUn9gIbZKVagQrKnytjccZOhcIC6msrKS5kBRnpOVFi8I1fNVZ5AbP6hKfU5W8BU+no3DAhF+yQqCfiPgmCJBnpr7OL/W7OMupzG9RveYLllOpAdA1z0TgiU9oAvWIrFdDSm1HKI83qm8Csy6RFVjM7lwsolkaW6gNOSMhEYWQ4i2O7F8ZDsrU/6+lhpfDiteM6r0BRWrr4pxB4u1Xkdh9u3fIJgul5AFoURCn97nWS1FkvlqlR99LWSO+OkGXv5Y3k7/PJQv1XV3YurUodqDrtgX8ZpEMIAiW+mB4/dosrdaH0yRffVOm0DT8ABldcUvkCJAxLffFLZl47tsGLan2/NNvXe+Va0zsqEmmtfSYU1PfWrSspNZU62wlClDzd0nTTNxzZb6q3OqT9VvrVoT+W1781oTVTh0JipNaXfsN1hX94ZsGiYklUSRZdL9ZxQ9M95lAFYISlJweH0xKQ0BqDgkoPM2DbC9CIjYc70Z5CAncAYMnowDK/Db8eCVsaZDPi94Q9lW5zX7MuxOBFrnrgGbL+BYqMz+Qpw/VguXKSfmV0+4yjz1JdNbqMpu2WDPxaIVjI1J1wusyWBsdUJqfm62ujAN02oylufaRyirbC0xJ3BuaQln57Hxbx57Tx7rFtEfQ1AaERLMLyiFsi3Bau26MWon1gXfUWKhsmOGVo9RmYvUmOqh/DnMPW3+KJecaqlZqy5jIeT3P1MJk70oMspQaKzJIxhrSJDBuCw+ZTuT7aryTJi8aVuIuEhkUerJP/lwDZUSENHdtBCxWZai9gKqPTPbXHS6jCw9uVJ9mZvGnm04k2M5se2ODd/uWvdg9KQp8x3o6exc8n9xhG3tYkg70vwsS4xbZVLnhmhglrBP+G7nXNFpQ0SZShvBxFNtlU07rmrvQ5NsbGuNIQPTqQm29WtFpvb3Sa+NTG675B7a5k64OTm7zTUs7mVr01lUI4PaNYYv+ILf5ngec4Tm/r8tquH7/1lxrv4D -------------------------------------------------------------------------------- /tools/CosmosEmulator/CosmosEmulator.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net6.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /tools/CosmosEmulator/CosmosInitializer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Threading.Tasks; 4 | using Microsoft.Azure.Cosmos; 5 | 6 | namespace CosmosEmulator 7 | { 8 | internal class CosmosInitializer 9 | { 10 | // Hardcoded in the emulator 11 | const string ConnectionString = "AccountEndpoint=https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw=="; 12 | const string DbName = "2wr"; 13 | 14 | internal async Task Run() 15 | { 16 | try 17 | { 18 | Console.WriteLine($"Creating Cosmos Client"); 19 | var client = new CosmosClient(ConnectionString); 20 | Console.WriteLine($"Creating Database: {DbName}"); 21 | var db = await client.CreateDatabaseIfNotExistsAsync(DbName); 22 | switch (db.StatusCode) 23 | { 24 | case HttpStatusCode.OK: 25 | Console.WriteLine($"Database Already Existed: {DbName}"); 26 | break; 27 | case HttpStatusCode.Created: 28 | Console.WriteLine($"Database Created: {DbName}"); 29 | break; 30 | default: 31 | { 32 | Console.WriteLine($"Database failed to Create: {DbName}"); 33 | return -1; 34 | } 35 | } 36 | 37 | var collections = new [] 38 | { 39 | (name: "basekits", key: "/id"), 40 | (name: "emergencykits", key: "/userId"), 41 | (name: "familymembers", key: "/id"), 42 | (name: "familyplans", key: "/userid"), 43 | (name: "hazardhunts", key: "/id"), 44 | (name: "hazardinformation", key: "/id") 45 | }; 46 | 47 | foreach (var collection in collections) 48 | { 49 | Console.WriteLine($"Creating collection: {collection.name}"); 50 | var response = await db.Database.CreateContainerIfNotExistsAsync(collection.name, collection.key, 400); 51 | switch (db.StatusCode) 52 | { 53 | case HttpStatusCode.Created: 54 | Console.WriteLine($"Created Container {collection.name} Successfully."); 55 | break; 56 | case HttpStatusCode.OK: 57 | Console.WriteLine($"Container {collection.name} Exists."); 58 | break; 59 | default: 60 | { 61 | Console.WriteLine($"Collection failed to Create: {collection.name}."); 62 | return -1; 63 | } 64 | } 65 | }; 66 | 67 | Console.WriteLine($"Setup complete...."); 68 | 69 | return 0; 70 | } 71 | catch (Exception ex) 72 | { 73 | Console.WriteLine($"Failed to setup Emulator: {ex}"); 74 | } 75 | 76 | return -1; 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /tools/CosmosEmulator/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace CosmosEmulator 5 | { 6 | class Program 7 | { 8 | static async Task Main(string[] args) 9 | { 10 | if (args.Length == 1 && args[0].ToLower() == "/setup") 11 | { 12 | Console.WriteLine("Starting to setup the CosmosDB Emulator."); 13 | return await new CosmosInitializer().Run(); 14 | } 15 | else 16 | { 17 | Console.WriteLine("No command specified."); 18 | return 0; 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /tools/CosmosEmulator/start-emulator.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Setup CosmosDB Docker Emulator 4 | ipaddr="`ifconfig | grep "inet " | grep -Fv 127.0.0.1 | awk '{print $2}' | head -n 1`" 5 | docker pull mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator 6 | 7 | # start emulator 8 | docker run --detach --rm -p 8081:8081 -p 10251:10251 -p 10252:10252 -p 10253:10253 -p 10254:10254 -m 3g --cpus=2.0 --name=test-linux-emulator -e AZURE_COSMOS_EMULATOR_PARTITION_COUNT=10 -e AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE=true -e AZURE_COSMOS_EMULATOR_IP_ADDRESS_OVERRIDE=$ipaddr -it mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator & 9 | 10 | # wait for process to complete and server to start 11 | wait 12 | sleep 120s # necessary wait time for the cosmosdb server to start up and start responding to web requests 13 | 14 | # install the certificate 15 | curl --insecure --url https://localhost:8081/_explorer/emulator.pem -o ~/emulatorcert.crt 16 | sudo cp ~/emulatorcert.crt /usr/local/share/ca-certificates/emulatorcert.crt 17 | sudo update-ca-certificates 18 | 19 | # setup database tables 20 | pushd ./tools/CosmosEmulator 21 | dotnet run /setup 22 | popd 23 | -------------------------------------------------------------------------------- /tools/CosmosEmulator/stop-emulator.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # stop docker process 4 | docker stop test-linux-emulator 5 | 6 | # remove SSL certificate 7 | sudo rm /usr/local/share/ca-certificates/emulatorcert.crt 8 | sudo update-ca-certificates -------------------------------------------------------------------------------- /tools/first-build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # restore and build dotnet projects (api & admin) 4 | dotnet restore ./TwoWeeksReady.Common 5 | dotnet restore ./api/api.sln 6 | dotnet restore ./admin/admin.sln 7 | dotnet build ./TwoWeeksReady.Common 8 | dotnet build ./api/api.sln 9 | dotnet build ./admin/admin.sln 10 | 11 | # restore Vue app (2wr-app) 12 | pushd ./2wr-app 13 | npm install 14 | npm install -g azurite 15 | npx playwright install 16 | npm run build 17 | popd 18 | 19 | # setup default configuration files 20 | bash ./tools/setup-config.sh > /dev/null -------------------------------------------------------------------------------- /tools/samples/local.settings.sample.json: -------------------------------------------------------------------------------- 1 | { 2 | "IsEncrypted": false, 3 | "Values": { 4 | "AzureWebJobsStorage": "UseDevelopmentStorage=true", 5 | "FUNCTIONS_WORKER_RUNTIME": "dotnet", 6 | "OidcApiAuthSettings:Audience": "https://2wrdev.azurewebsites.net", 7 | "OidcApiAuthSettings:IssuerUrl": "https://login.2wr.org/" 8 | }, 9 | "ConnectionStrings": { 10 | "CosmosDBConnection": "AccountEndpoint=https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==", 11 | "StorageConnection": "UseDevelopmentStorage=true" 12 | }, 13 | "Host":{ 14 | "CORS": "*" 15 | } 16 | } -------------------------------------------------------------------------------- /tools/setup-config.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # navigate to script directory 4 | SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) 5 | pushd $SCRIPT_DIR 6 | 7 | # create api settings file from sample 8 | API_SETTINGS_FILE=../api/TwoWeeksReady/local.settings.json 9 | if [[ ! -f $API_SETTINGS_FILE ]] 10 | then 11 | cp ./samples/local.settings.sample.json $API_SETTINGS_FILE 12 | fi 13 | 14 | # create 2wr-app env from sample 15 | APP_SETTINGS_FILE=../2wr-app/.env 16 | if [[ ! -f $APP_SETTINGS_FILE ]] 17 | then 18 | cp ../2wr-app/.env-sample $APP_SETTINGS_FILE 19 | fi 20 | popd --------------------------------------------------------------------------------