Skip to content
Open
20 changes: 10 additions & 10 deletions src/components/Dashboard/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
documentTextOutline, cloudUploadOutline, cloudDownloadOutline, shareSocialOutline, trashOutline,
addCircleOutline, serverOutline, hardwareChipOutline, openOutline, timeOutline, statsChartOutline, searchOutline, documentOutline
} from "ionicons/icons";
import { Local, File as LocalFile, BackupRecord, ActivityLog, AppMetrics } from "../Storage/LocalStorage";
import { Local, File as LocalFile, FileData, FileListItem, BackupRecord, ActivityLog, AppMetrics } from "../Storage/LocalStorage";
import { backupInvoiceToIPFS, restoreInvoiceFromIPFS, testConnection } from "../../services/MeshkitService";
import { BackupSuccessModal } from "../Modals/BackupSuccessModal";
import { RestoreSuccessModal } from "../Modals/RestoreSuccessModal";
Expand All @@ -23,7 +23,7 @@ interface DashboardProps {
}

const Dashboard: React.FC<DashboardProps> = ({ store, onOpenFile, currentBillType }) => {
const [fileList, setFileList] = useState<{ [key: string]: any }>({});
const [fileList, setFileList] = useState<Record<string, FileListItem>>({});
const [backupHistory, setBackupHistory] = useState<BackupRecord[]>([]);
const [activityLogs, setActivityLogs] = useState<ActivityLog[]>([]);
const [metrics, setMetrics] = useState<AppMetrics>({ invoicesCreated: 0, invoicesBackedUp: 0, successfulRestores: 0, filesUploaded: 0, messagesSent: 0 });
Expand Down Expand Up @@ -88,7 +88,7 @@ const Dashboard: React.FC<DashboardProps> = ({ store, onOpenFile, currentBillTyp
};

const handleOpen = (key: string) => {
store._getFile(key).then((data: any) => {
store._getFile(key).then((data: FileData) => {
AppGeneral.viewFile(key, decodeURIComponent(data.content));
onOpenFile(key, data.billType);
});
Expand All @@ -97,7 +97,7 @@ const Dashboard: React.FC<DashboardProps> = ({ store, onOpenFile, currentBillTyp
const handleBackup = async (key: string) => {
setIsLoading(true);
try {
const data: any = await store._getFile(key);
const data: FileData = await store._getFile(key);
const record = await backupInvoiceToIPFS({
name: key,
created: data.created,
Expand Down Expand Up @@ -203,7 +203,7 @@ const Dashboard: React.FC<DashboardProps> = ({ store, onOpenFile, currentBillTyp
displayToast("Filename already exists");
return;
}
const content = encodeURIComponent(JSON.stringify(DATA["home"][AppGeneral.getDeviceType()]["msc"]));
const content = encodeURIComponent(JSON.stringify(DATA["home"][AppGeneral.getDeviceType() as keyof typeof DATA["home"]]["msc"]));
const file = new LocalFile(new Date().toString(), new Date().toString(), content, filename, currentBillType);
await store._saveFile(file);
await store._incrementMetric('invoicesCreated');
Expand Down Expand Up @@ -305,7 +305,7 @@ const Dashboard: React.FC<DashboardProps> = ({ store, onOpenFile, currentBillTyp
</IonBadge>
{fileList[key].cid && (
<span style={{ marginLeft: '10px', fontSize: '0.85em', color: 'var(--ion-color-medium)' }}>
CID: {fileList[key].cid.substring(0, 8)}...
CID: {fileList[key].cid?.substring(0, 8)}...
</span>
)}
</div>
Expand All @@ -316,13 +316,13 @@ const Dashboard: React.FC<DashboardProps> = ({ store, onOpenFile, currentBillTyp
<IonButton size="small" fill="outline" onClick={() => handleBackup(key)}>
<IonIcon icon={cloudUploadOutline} slot="start" /> Backup
</IonButton>
{fileList[key].backedUp && (
<IonButton size="small" fill="outline" color="secondary" onClick={() => handleRestore(fileList[key].cid, key)}>
{fileList[key].backedUp && fileList[key].cid && (
<IonButton size="small" fill="outline" color="secondary" onClick={() => handleRestore(fileList[key].cid!, key)}>
<IonIcon icon={cloudDownloadOutline} slot="start" /> Restore
</IonButton>
)}
{fileList[key].backedUp && (
<IonButton size="small" fill="outline" color="tertiary" onClick={() => handleShare(fileList[key].cid)}>
{fileList[key].backedUp && fileList[key].cid && (
<IonButton size="small" fill="outline" color="tertiary" onClick={() => handleShare(fileList[key].cid!)}>
<IonIcon icon={shareSocialOutline} slot="start" /> Share
</IonButton>
)}
Expand Down
26 changes: 14 additions & 12 deletions src/components/Files/Files.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React, { useState, useEffect } from "react";
import "./Files.css";
import * as AppGeneral from "../socialcalc/index.js";
import { DATA } from "../../app-data.js";
import { File as LocalFile, Local, BackupRecord } from "../Storage/LocalStorage";
import { File as LocalFile, Local, FileData, FileListItem, BackupRecord } from "../Storage/LocalStorage";
import {
IonIcon,
IonModal,
Expand All @@ -26,18 +26,20 @@ import {
import { fileTrayFull, ellipsisVertical, cloudUploadOutline, cloudDownloadOutline, shareSocialOutline, trash, folderOpenOutline, timeOutline } from "ionicons/icons";
import { backupInvoiceToIPFS, restoreInvoiceFromIPFS } from "../../services/MeshkitService";

const Files: React.FC<{
interface FilesProps {
store: Local;
file: string;
updateSelectedFile: Function;
updateBillType: Function;
}> = (props) => {
updateSelectedFile: (file: string) => void;
updateBillType: (billType: number) => void;
}

const Files: React.FC<FilesProps> = (props) => {
const [modal, setModal] = useState<JSX.Element | null>(null);
const [listFiles, setListFiles] = useState(false);
const [showAlertDelete, setShowAlertDelete] = useState(false);
const [currentKey, setCurrentKey] = useState<string | null>(null);

const [fileList, setFileList] = useState<{ [key: string]: any }>({});
const [fileList, setFileList] = useState<Record<string, FileListItem>>({});

const [actionSheetOpen, setActionSheetOpen] = useState(false);
const [selectedActionFile, setSelectedActionFile] = useState<string | null>(null);
Expand Down Expand Up @@ -71,7 +73,7 @@ const Files: React.FC<{
};

const editFile = (key: string) => {
props.store._getFile(key).then((data: any) => {
props.store._getFile(key).then((data: FileData) => {
AppGeneral.viewFile(key, decodeURIComponent(data.content));
props.updateSelectedFile(key);
props.updateBillType(data.billType);
Expand All @@ -85,7 +87,7 @@ const Files: React.FC<{
};

const loadDefault = () => {
const msc = DATA["home"][AppGeneral.getDeviceType()]["msc"];
const msc = DATA["home"][AppGeneral.getDeviceType() as keyof typeof DATA["home"]]["msc"];
AppGeneral.viewFile("default", JSON.stringify(msc));
props.updateSelectedFile("default");
};
Expand All @@ -98,7 +100,7 @@ const Files: React.FC<{
const handleBackup = async (key: string) => {
setIsLoading(true);
try {
const data: any = await props.store._getFile(key);
const data: FileData = await props.store._getFile(key);
const record = await backupInvoiceToIPFS({
name: key,
created: data.created,
Expand Down Expand Up @@ -185,16 +187,16 @@ const Files: React.FC<{
}
];

if (isBackedUp) {
if (isBackedUp && fileData.cid) {
buttons.push({
text: 'Restore (Overwrite Local)',
icon: cloudDownloadOutline,
handler: () => handleRestore(selectedActionFile, fileData.cid)
handler: () => handleRestore(selectedActionFile, fileData.cid!)
});
buttons.push({
text: 'Share',
icon: shareSocialOutline,
handler: () => handleShare(fileData.cid)
handler: () => handleShare(fileData.cid!)
});
}

Expand Down
42 changes: 23 additions & 19 deletions src/components/Menu/Menu.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useState } from "react";
import * as AppGeneral from "../socialcalc/index.js";
import { File, Local } from "../Storage/LocalStorage";
import { File, Local, FileData } from "../Storage/LocalStorage";
import { isPlatform, IonToast } from "@ionic/react";
import { EmailComposer } from "capacitor-email-composer";
import { Printer } from "@ionic-native/printer";
Expand All @@ -10,14 +10,16 @@ import { APP_NAME } from "../../app-data.js";
import { backupInvoiceToIPFS, restoreInvoiceFromIPFS } from "../../services/MeshkitService";
import { BackupSuccessModal } from "../Modals/BackupSuccessModal";

const Menu: React.FC<{
interface MenuProps {
showM: boolean;
setM: Function;
setM: () => void;
file: string;
updateSelectedFile: Function;
updateSelectedFile: (file: string) => void;
store: Local;
bT: number;
}> = (props) => {
}

const Menu: React.FC<MenuProps> = (props) => {
const [showAlert1, setShowAlert1] = useState(false);
const [showAlert2, setShowAlert2] = useState(false);
const [showAlert3, setShowAlert3] = useState(false);
Expand All @@ -35,7 +37,7 @@ const Menu: React.FC<{
const [showAlertRestoreError, setShowAlertRestoreError] = useState(false);

/* Utility functions */
const _validateName = async (filename) => {
const _validateName = async (filename: string) => {
filename = filename.trim();
if (filename === "default" || filename === "Untitled") {
setToastMessage("Cannot update default file!");
Expand All @@ -58,7 +60,7 @@ const Menu: React.FC<{
const getCurrentFileName = () => {
return props.file;
};
const _formatString = (filename) => {
const _formatString = (filename: string) => {
/* Remove whitespaces */
while (filename.indexOf(" ") !== -1) {
filename = filename.replace(" ", "");
Expand All @@ -72,29 +74,31 @@ const Menu: React.FC<{
} else {
const content = AppGeneral.getCurrentHTMLContent();
const printWindow = window.open("/printwindow", "Print Invoice");
printWindow.document.write(content);
printWindow.print();
if (printWindow) {
printWindow.document.write(content);
printWindow.print();
}
}
};
const doSave = () => {
const doSave = async () => {
if (props.file === "default") {
setShowAlert1(true);
return;
}
const content = encodeURIComponent(AppGeneral.getSpreadsheetContent());
const data = props.store._getFile(props.file);
const data = await props.store._getFile(props.file);
const file = new File(
(data as any).created,
data.created,
new Date().toString(),
content,
props.file,
props.bT
);
props.store._saveFile(file);
await props.store._saveFile(file);
props.updateSelectedFile(props.file);
setShowAlert2(true);
};
const doSaveAs = async (filename) => {
const doSaveAs = async (filename: string) => {
if (filename) {
if (await _validateName(filename)) {
const content = encodeURIComponent(AppGeneral.getSpreadsheetContent());
Expand Down Expand Up @@ -123,7 +127,7 @@ const Menu: React.FC<{
const content = encodeURIComponent(AppGeneral.getSpreadsheetContent());
const record = await backupInvoiceToIPFS({
name: props.file,
created: (data as any).created,
created: data.created,
modified: new Date().toString(),
billType: props.bT,
content,
Expand All @@ -132,9 +136,9 @@ const Menu: React.FC<{

// Update local file metadata
const file = new File(
(data as any).created,
(data as any).modified, // Keep original modified date
(data as any).content,
data.created,
data.modified, // Keep original modified date
data.content,
props.file,
props.bT,
true, // backedUp
Expand All @@ -156,7 +160,7 @@ const Menu: React.FC<{
}
};

const doRestoreFromIPFS = async (cid) => {
const doRestoreFromIPFS = async (cid: string) => {
if (!cid) return;
try {
const backup = await restoreInvoiceFromIPFS(cid);
Expand Down
20 changes: 11 additions & 9 deletions src/components/NewFile/NewFile.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,34 @@
import React, { useState } from "react";
import * as AppGeneral from "../socialcalc/index.js";
import { File, Local } from "../Storage/LocalStorage";
import { File, Local, FileData } from "../Storage/LocalStorage";
import { DATA } from "../../app-data.js";
import { IonAlert, IonIcon } from "@ionic/react";
import { add } from "ionicons/icons";

const NewFile: React.FC<{
interface NewFileProps {
file: string;
updateSelectedFile: Function;
updateSelectedFile: (file: string) => void;
store: Local;
billType: number;
}> = (props) => {
}

const NewFile: React.FC<NewFileProps> = (props) => {
const [showAlertNewFileCreated, setShowAlertNewFileCreated] = useState(false);
const newFile = () => {
const newFile = async () => {
if (props.file !== "default") {
const content = encodeURIComponent(AppGeneral.getSpreadsheetContent());
const data = props.store._getFile(props.file);
const data: FileData = await props.store._getFile(props.file);
const file = new File(
(data as any).created,
data.created,
new Date().toString(),
content,
props.file,
props.billType
);
props.store._saveFile(file);
await props.store._saveFile(file);
props.updateSelectedFile(props.file);
}
const msc = DATA["home"][AppGeneral.getDeviceType()]["msc"];
const msc = DATA["home"][AppGeneral.getDeviceType() as keyof typeof DATA["home"]]["msc"];
AppGeneral.viewFile("default", JSON.stringify(msc));
props.updateSelectedFile("default");
setShowAlertNewFileCreated(true);
Expand Down
39 changes: 30 additions & 9 deletions src/components/Storage/LocalStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,24 @@ export interface AppMetrics {
messagesSent: number;
}

export interface FileData {
created: string;
modified: string;
content: string;
name: string;
billType: number;
backedUp?: boolean;
cid?: string;
lastBackupAt?: string;
}

export interface FileListItem {
modified: string;
backedUp?: boolean;
cid?: string;
lastBackupAt?: string;
}

export class File {
created: string;
modified: string;
Expand Down Expand Up @@ -71,23 +89,26 @@ export class Local {
});
};

_getFile = async (name: string) => {
_getFile = async (name: string): Promise<FileData> => {
const rawData = await Preferences.get({ key: name });
return JSON.parse(rawData.value);
if (!rawData.value) {
throw new Error(`File "${name}" not found in storage`);
}
return JSON.parse(rawData.value) as FileData;
};

_getAllFiles = async () => {
let arr = {};
_getAllFiles = async (): Promise<Record<string, FileListItem>> => {
const arr: Record<string, FileListItem> = {};
const { keys } = await Preferences.keys();
for (let i = 0; i < keys.length; i++) {
let fname = keys[i];
const fname = keys[i];
if (fname === "_MeshKit_BackupHistory" || fname === "_MeshKit_ActivityLogs" || fname === "_MeshKit_Metrics") continue;
const data = await this._getFile(fname);
arr[fname] = {
modified: (data as any).modified,
backedUp: (data as any).backedUp,
cid: (data as any).cid,
lastBackupAt: (data as any).lastBackupAt,
modified: data.modified,
backedUp: data.backedUp,
cid: data.cid,
lastBackupAt: data.lastBackupAt,
};
}
return arr;
Expand Down
4 changes: 2 additions & 2 deletions src/pages/Home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const Home: React.FC = () => {
}>({ open: false, event: undefined });
const [selectedFile, updateSelectedFile] = useState("default");
const [billType, updateBillType] = useState(1);
const [device] = useState("default");
const [device] = useState<"default">("default");
const history = useHistory();

const store = new Local();
Expand All @@ -43,7 +43,7 @@ const Home: React.FC = () => {
setShowMenu(false);
};

const activateFooter = (footer) => {
const activateFooter = (footer: number) => {
AppGeneral.activateFooterButton(footer);
};

Expand Down
Loading