Skip to content

Commit

Permalink
Merge pull request #48 from pushme-tgxn/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
tgxn authored Dec 21, 2022
2 parents 6bbce05 + da32492 commit 9b2ebc3
Show file tree
Hide file tree
Showing 21 changed files with 12,790 additions and 12,719 deletions.
9 changes: 9 additions & 0 deletions .github/workflows/todo-to-issue.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name: "Run TODO to Issue"
on: ["push"]
jobs:
build:
runs-on: "ubuntu-latest"
steps:
- uses: "actions/checkout@v3"
- name: "TODO to Issue"
uses: "alstr/todo-to-issue-action@v4"
87 changes: 72 additions & 15 deletions App.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,16 @@ import {
import AuthView from "./views/AuthView";
import AppTabView from "./views/AppTabView";

import { AppReducer, NotificationCategories } from "./const";
import NotificationPopup from "./components/NotificationPopup";

import { NotificationDefinitions } from "@pushme-tgxn/pushmesdk";

import { AppReducer } from "./const";

import apiService from "./service/api";

import { Alert, Linking } from "react-native";

// background notificaiton listener
const BACKGROUND_NOTIFICATION_TASK = "BACKGROUND-NOTIFICATION-TASK";
TaskManager.defineTask(BACKGROUND_NOTIFICATION_TASK, ({ data, error, executionInfo }) => {
Expand Down Expand Up @@ -115,9 +121,18 @@ const App = () => {
finalStatus = status;
}

const openAppSettings = () => {
Linking.openSettings();
};

if (finalStatus !== "granted") {
alert("Failed to get push token for push notification!");
return;
Alert.alert(
`Notification Permissions were not granted`,
"Please enable notifications in this app's settings.",
[{ text: "Thanks" }, { text: "Open App Settings", onPress: openAppSettings }],
);

return [null, null];
}

token = await Notifications.getExpoPushTokenAsync();
Expand All @@ -131,16 +146,19 @@ const App = () => {

// register notification categories from client-side
const registerNotificationCategories = async () => {
for (const index in NotificationCategories) {
await Notifications.setNotificationCategoryAsync(index, NotificationCategories[index]);
for (const index in NotificationDefinitions) {
const notificationCategory = NotificationDefinitions[index];
if (notificationCategory.actions) {
console.debug("registering notification actions", index, notificationCategory);
await Notifications.setNotificationCategoryAsync(index, notificationCategory.actions);
}
}
};

useEffect(() => {
async function prepare() {
let deviceKey, loggedInUser;

// generate or load a unique device key, and save it.
let deviceKey;
try {
const existingDeviceKey = await AsyncStorage.getItem("deviceKey");
if (existingDeviceKey !== null) {
Expand All @@ -159,13 +177,19 @@ const App = () => {
// get application push tokens, and register notification categories
try {
let [expoToken, nativeToken] = await registerForPushNotificationsAsync();
dispatch(setExpoPushToken(expoToken));
dispatch(setNativePushToken(nativeToken));

if (expoToken) {
dispatch(setExpoPushToken(expoToken));
}

if (nativeToken) {
dispatch(setNativePushToken(nativeToken));
}

await registerNotificationCategories();
} catch (error) {
console.error("error setting app up", error);
alert("error setting app up: " + error.toString());
// alert("error setting app up: " + error.toString());
}

// attempt to load backend URL
Expand All @@ -179,6 +203,7 @@ const App = () => {
}

// attempt to load user
let loggedInUser;
try {
const serializedUserData = await AsyncStorage.getItem("userData");
if (serializedUserData !== null) {
Expand Down Expand Up @@ -214,20 +239,51 @@ const App = () => {

await SplashScreen.hideAsync();
}

prepare();

// notification recieved, append to local array
notificationListener.current = Notifications.addNotificationReceivedListener((notification) => {
console.log("addNotificationReceivedListener", notification);
dispatch(pushRecieved(notification));

// Notifications.dismissNotificationAsync(notification.request.identifier);
});

// notification response recieved
responseListener.current = Notifications.addNotificationResponseReceivedListener((response) => {
console.log("addNotificationResponseReceivedListener", response);
dispatch(setPushResponse(response));
console.log("addNotificationResponseReceivedListener", JSON.stringify(response, null, 4));

// get the notification response data
// TODO define this payload format
const responseData = {
pushIdent: response.notification.request.content.data.pushIdent,
pushId: response.notification.request.content.data.pushId,
actionIdentifier: response.actionIdentifier,
categoryIdentifier: response.notification.request.content.categoryIdentifier,
responseText: null,
};

// asttach user text is defined
if (response.userText) {
responseData.responseText = response.userText;
}

let foundNotificatonCategory = false;
for (const index in NotificationDefinitions) {
const notificationCategory = NotificationDefinitions[index];
if (index == responseData.categoryIdentifier) {
foundNotificatonCategory = notificationCategory;
}
}

// send non-default responses if enabled for this type of notification
if (response.actionIdentifier == Notifications.DEFAULT_ACTION_IDENTIFIER) {
if (foundNotificatonCategory && foundNotificatonCategory.sendDefaultAction) {
dispatch(setPushResponse(responseData));
}
} else {
dispatch(setPushResponse(responseData));
}

// dismiss the notificaqtion when it's tapped
Notifications.dismissNotificationAsync(response.notification.request.identifier);
});

Expand Down Expand Up @@ -256,6 +312,7 @@ const App = () => {
theme={theme}
>
<NavigationContainer theme={theme}>
<NotificationPopup />
<StatusBar
backgroundColor={theme.colors.background}
style={scheme === "dark" ? "light" : "dark"}
Expand Down
3 changes: 0 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ API Docs can be found on the server.

## Features

@TODO
[Unhandled promise rejection: Error: Background remote notifications have not been configured. To enable it, add `remote-notification` to `UIBackgroundModes` in the application's Info.plist file.]

- diudn't create tables before mariadb was available (docker)

## Colors
Expand Down
6 changes: 3 additions & 3 deletions app.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"description": "Simple Push Notifications & Approvals",
"slug": "pushme",
"originalFullName": "@tgxn/pushme",
"version": "2.0.3",
"githubUrl": "https://github.com/pushme-tgxn-net/PushMeApp",
"version": "2.0.7",
"githubUrl": "https://github.com/pushme-tgxn/PushMeApp",
"orientation": "portrait",
"userInterfaceStyle": "automatic",
"primaryColor": "#A845FF",
Expand All @@ -24,7 +24,7 @@
},
"android": {
"icon": "./assets/logo.png",
"versionCode": 203,
"versionCode": 207,
"permissions": [],
"package": "net.tgxn.pushme",
"adaptiveIcon": {
Expand Down
4 changes: 2 additions & 2 deletions components/CustomNavigationBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,15 +76,15 @@ function ViewDeviceButtons({ navigation, deviceData }) {
const [deleteVisible, setDeleteVisible] = useState(false);

const saveDevice = async () => {
await apiService.device.upsertDevice(deviceData.deviceKey, {
await apiService.device.update(deviceData.deviceKey, {
name: deviceName,
});

setEditVisible(false);
};

const deleteDevice = async () => {
await apiService.device.deleteDevice(deviceData.id);
await apiService.device.delete(deviceData.id);

setDeleteVisible(false);
navigation.navigate("ConfigScreen", { refresh: true });
Expand Down
132 changes: 132 additions & 0 deletions components/NotificationPopup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import React, { useState, useContext } from "react";

import { SafeAreaView, View, useColorScheme } from "react-native";

import {
Appbar,
Menu,
IconButton,
Colors,
Button,
Modal,
Dialog,
Portal,
Paragraph,
} from "react-native-paper";

import * as Notifications from "expo-notifications";
// import { Picker } from "@react-native-picker/picker";

// import { PaperSelect } from "react-native-paper-select";

import DropDown from "react-native-paper-dropdown";

import { Separator } from "../components/Shared";

import { useTheme } from "react-native-paper";

import { AppReducer } from "../const";
import { setPushResponse } from "../reducers/app";

import apiService from "../service/api";
import styles from "../styles";

export default function NotificationPopup() {
const theme = useTheme();
const colorScheme = useColorScheme();

const { state, dispatch } = useContext(AppReducer);

const [visible, setVisible] = useState(false);
const [loading, setLoading] = useState(false);

const [pushContent, setPushContent] = useState(null);

const themedStyles = styles(colorScheme);

const lastNotificationResponse = Notifications.useLastNotificationResponse();

React.useEffect(() => {
if (!lastNotificationResponse) return;

console.log("lastNotificationResponse", lastNotificationResponse);
setPushContent(lastNotificationResponse.notification.request.content);

// only load for the default type
if (
lastNotificationResponse &&
lastNotificationResponse.actionIdentifier === Notifications.DEFAULT_ACTION_IDENTIFIER
) {
setVisible(true);
}
}, [lastNotificationResponse]);

// TODO build a list of categories and functions to generate action buttons

return (
<Portal>
<Modal
style={{ backgroundColor: "#000000FF" }}
visible={visible}
onDismiss={() => setVisible(false)}
contentContainerStyle={{
backgroundColor: theme.colors.backdrop,
margin: 20,
}}
>
<Dialog.Title>Incoming Push</Dialog.Title>
<Dialog.Content>
{lastNotificationResponse && pushContent && (
<View>
<Paragraph>
actionIdentifier: {lastNotificationResponse.actionIdentifier}
</Paragraph>
<Paragraph>title: {pushContent.title}</Paragraph>
<Paragraph>body: {pushContent.body}</Paragraph>
<Paragraph>categoryIdentifier: {pushContent.categoryIdentifier}</Paragraph>
<Paragraph>pushIdent: {pushContent.data.pushIdent}</Paragraph>
<Paragraph>pushId: {pushContent.data.pushId}</Paragraph>
<Separator />
<Paragraph>{JSON.stringify(lastNotificationResponse)}</Paragraph>
</View>
)}
</Dialog.Content>
<Dialog.Actions>
<Button onPress={() => setVisible(false)}>Thanks</Button>
<Button
onPress={() => {
const responseData = {
pushIdent: pushContent.data.pushIdent,
pushId: pushContent.data.pushId,
actionIdentifier: "reject", // TODO must get the actionIdentifier from the button AND categoryIdentifier OF REQUEST
categoryIdentifier: pushContent.categoryIdentifier,
responseText: null,
};
dispatch(setPushResponse(responseData));
setVisible(false);
}}
loading={loading}
>
Reject
</Button>
<Button
onPress={() => {
const responseData = {
pushIdent: pushContent.data.pushIdent,
pushId: pushContent.data.pushId,
actionIdentifier: "approve", // TODO must get the actionIdentifier from the button AND categoryIdentifier OF REQUEST
categoryIdentifier: pushContent.categoryIdentifier,
responseText: null,
};
dispatch(setPushResponse(responseData));
setVisible(false);
}}
loading={loading}
>
Approve
</Button>
</Dialog.Actions>
</Modal>
</Portal>
);
}
27 changes: 7 additions & 20 deletions components/PushPopup.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,15 @@ import React, { useState } from "react";

import { SafeAreaView, Text, View, useColorScheme, StyleSheet, FlatList, ScrollView } from "react-native";

import {
Appbar,
Menu,
IconButton,
Colors,
Button,
Modal,
Dialog,
Portal,
TextInput,
} from "react-native-paper";

// import { Picker } from "@react-native-picker/picker";

// import { PaperSelect } from "react-native-paper-select";
import { Button, Modal, Dialog, Portal, TextInput } from "react-native-paper";

import { NotificationDefinitions } from "@pushme-tgxn/pushmesdk";

import DropDown from "react-native-paper-dropdown";

import { useTheme } from "react-native-paper";
import apiService from "../service/api";

import { NotificationCategories } from "../const";

import styles from "../styles";

export default function PushPopup({ visible, setVisible, topicData, secretKey }) {
Expand Down Expand Up @@ -53,10 +39,11 @@ export default function PushPopup({ visible, setVisible, topicData, secretKey })
setVisible(false);
};

// generate list of push types
let clientCategoryList = [{ value: "default", label: "Default" }];
// NotificationCategories;
for (const index in NotificationCategories) {
clientCategoryList.push({ value: index, label: index });
for (const index in NotificationDefinitions) {
const notificationCategory = NotificationDefinitions[index];
clientCategoryList.push({ value: index, label: notificationCategory.title });
}

console.log("clientCategoryList", clientCategoryList);
Expand Down
Loading

0 comments on commit 9b2ebc3

Please sign in to comment.