moved modal on expenseModal.ts. Some cosmetics: setCta & remove, add form validation before posting

This commit is contained in:
steeven 2024-04-12 19:29:19 +02:00
parent 9d7f899386
commit 47e238ff48
2 changed files with 221 additions and 180 deletions

199
expenseModal.ts Normal file
View File

@ -0,0 +1,199 @@
import {
App,
Modal,
Notice,
ButtonComponent,
MarkdownView,
Setting,
} from "obsidian";
import budgetPlugin from "./main";
import { DEFAULT_SETTINGS } from "./main";
export class ExpenseModal extends Modal {
plugin: budgetPlugin = DEFAULT_SETTINGS;
expenseAmount: string;
expenseAccount: string;
expenseCategory: string;
expenseValue: string;
onSubmit: (
expenseAmount: string,
expenseCategory: string,
expenseAccount: string,
expenseValue: string
) => void;
constructor(
app: App,
plugin: budgetPlugin,
onSubmit: (
expenseAmount: string,
expenseCategory: string,
expenseAccount: string,
expenseValue: string
) => void
) {
super(app);
this.plugin = plugin;
this.onSubmit = onSubmit;
}
async onOpen() {
const { contentEl } = this;
contentEl.createEl("h1", { text: "Enter new Expense" });
// get the data from the plugin settings
const pluginData = await this.plugin.loadData();
// create a currency formatter
// to do : get regional settings from obsidian
const formatter = new Intl.NumberFormat("fr-FR", {
style: "currency",
currency: pluginData.currency,
});
// input field for the expense amount
// todo: add focus on this field
new Setting(contentEl).setName("Amount").addText((text) =>
text.onChange((value) => {
this.expenseAmount = value;
})
);
// create category button with icon and tooltip
const categorySetting = new Setting(contentEl).setName("Category");
let selectedButton: ButtonComponent | null = null;
Object.entries(pluginData.expenseCategories).forEach(
([key, value]: [string, { icon: string; name: string }]) => {
categorySetting.addButton((btn: ButtonComponent) =>
btn
.setButtonText(key)
.setIcon(value.icon)
.setTooltip(value.name)
.onClick(() => {
// remove the cta from the previous button
if (selectedButton) {
selectedButton.removeCta();
}
selectedButton = btn;
this.expenseCategory = value.name;
new Notice(`Selected Category: ${value.name}`);
btn.setCta();
})
);
}
);
// create account button with icon and tooltip
const accountSetting = new Setting(contentEl).setName("Account");
let selectedButton2: ButtonComponent | null = null;
Object.entries(pluginData.expenseAccounts).forEach(
([key, value]: [string, { icon: string; name: string }]) => {
accountSetting.addButton((btn: ButtonComponent) =>
btn
.setButtonText(key)
.setIcon(value.icon)
.setTooltip(value.name)
.onClick(() => {
// remove the cta from the previous button
if (selectedButton2) {
selectedButton2.removeCta();
}
selectedButton2 = btn;
this.expenseAccount = value.name;
new Notice(`Selected Account: ${value.name}`);
btn.setCta();
})
);
}
);
const valueSetting = new Setting(contentEl).setName("Value");
let selectedButton3: ButtonComponent | null = null;
Object.entries(pluginData.expenseValues).forEach(
([key, value]: [string, { icon: string; name: string }]) => {
valueSetting.addButton((btn: ButtonComponent) =>
btn
.setButtonText(key)
.setIcon(value.icon)
.setTooltip(value.name)
.onClick(() => {
// remove the cta from the previous button
if (selectedButton3) {
selectedButton3.removeCta();
}
selectedButton3 = btn;
this.expenseValue = value.name;
new Notice(`Selected Value: ${value.name}`);
btn.setCta();
})
);
}
);
// submit button
new Setting(contentEl).addButton((btn) =>
btn
.setButtonText("Submit")
.setCta()
.onClick(() => {
// check if all fields are filled
if (
this.expenseAmount &&
this.expenseCategory &&
this.expenseAccount &&
this.expenseValue
) {
new Notice("Expense added");
this.close();
this.onSubmit(
this.expenseAmount,
this.expenseCategory,
this.expenseAccount,
this.expenseValue
);
const file = this.app.workspace.getActiveFile();
if (file) {
const editor =
this.app.workspace.getActiveViewOfType(
MarkdownView
);
if (editor) {
// get today date and format YYYY-MM-DD
const today = new Date();
const todayFormatted = today
.toISOString()
.split("T")[0];
// move the cursor on start of line 3
editor.editor.setCursor(2, 0);
// insert the new expense on line 3
editor.editor.replaceSelection(
`| ${todayFormatted} | ${formatter.format(
Number(this.expenseAmount)
)} | ${this.expenseCategory} | ${
this.expenseAccount
} | ${this.expenseValue} | \n`
);
}
} else {
console.log("Debug: no active file");
}
} else {
new Notice("Please fill all the fields");
return;
}
})
);
}
onClose() {
const { contentEl } = this;
contentEl.empty();
}
}

202
main.ts
View File

@ -12,6 +12,7 @@ import {
Setting, Setting,
setIcon, setIcon,
} from "obsidian"; } from "obsidian";
import { ExpenseModal } from "./expenseModal";
interface BudgetSettings { interface BudgetSettings {
expenseCategories: object; expenseCategories: object;
@ -19,7 +20,7 @@ interface BudgetSettings {
expenseValues: object; expenseValues: object;
} }
const DEFAULT_SETTINGS: BudgetSettings = { export const DEFAULT_SETTINGS: BudgetSettings = {
expenseCategories: [ expenseCategories: [
{ name: "Eat", icon: "carrot" }, { name: "Eat", icon: "carrot" },
{ name: "Home", icon: "home" }, { name: "Home", icon: "home" },
@ -46,31 +47,27 @@ export default class budgetPlugin extends Plugin {
async onload() { async onload() {
await this.loadSettings(); await this.loadSettings();
const ribbonIconEl = this.addRibbonIcon( this.addRibbonIcon("dollar-sign", "New Expense", (evt: MouseEvent) => {
"dollar-sign", new Notice("New Expense Modal");
"New Expense", // need to start modal
(evt: MouseEvent) => { new ExpenseModal(
new Notice("New Expense Modal"); this.app,
// need to start modal this,
new ExpenseModal( (
this.app, expenseAmount,
this, expenseCategory,
( expenseAccount,
expenseAmount, expenseValue
expenseCategory, ) => {
expenseAccount, new Notice(
expenseValue `${expenseAmount}, ${expenseCategory}, ${expenseAccount}, ${expenseValue}`
) => { );
new Notice( }
`${expenseAmount}, ${expenseCategory}, ${expenseAccount}, ${expenseValue}` ).open();
);
}
).open();
// need to set active md file to budget // need to set active md file to budget
console.log("Debug: trigger new expense modal from ribbon"); console.log("Debug: trigger new expense modal from ribbon");
} });
);
// Adds a setting tag so the user can configure the aspects of the plugin // Adds a setting tag so the user can configure the aspects of the plugin
this.addSettingTab(new ExpenseSettingTab(this.app, this)); this.addSettingTab(new ExpenseSettingTab(this.app, this));
} }
@ -90,161 +87,6 @@ export default class budgetPlugin extends Plugin {
onunload(): void {} onunload(): void {}
} }
export class ExpenseModal extends Modal {
plugin: budgetPlugin = DEFAULT_SETTINGS;
expenseAmount: string;
expenseAccount: string;
expenseCategory: string;
expenseValue: string;
onSubmit: (
expenseAmount: string,
expenseCategory: string,
expenseAccount: string,
expenseValue: string
) => void;
constructor(
app: App,
plugin: budgetPlugin,
onSubmit: (
expenseAmount: string,
expenseCategory: string,
expenseAccount: string,
expenseValue: string
) => void
) {
super(app);
this.plugin = plugin;
this.onSubmit = onSubmit;
}
async onOpen() {
const { contentEl } = this;
contentEl.createEl("h1", { text: "Enter new Expense" });
// get the data from the plugin settings
const pluginData = await this.plugin.loadData();
// create a currency formatter
const formatter = new Intl.NumberFormat("fr-FR", {
style: "currency",
currency: pluginData.currency,
});
// input field for the expense amount
new Setting(contentEl).setName("Amount").addText((text) =>
text.onChange((value) => {
this.expenseAmount = value;
})
);
// create category button with icon and tooltip
const categorySetting = new Setting(contentEl).setName("Category");
Object.entries(pluginData.expenseCategories).forEach(
([key, value]: [string, { icon: string; name: string }]) => {
categorySetting.addButton((btn: ButtonComponent) =>
btn
.setButtonText(key)
.setIcon(value.icon)
.setTooltip(value.name)
.onClick(() => {
this.expenseCategory = value.name;
new Notice(`Selected Category: ${value.name}`);
btn.setCta();
})
);
}
);
// create account button with icon and tooltip
const accountSetting = new Setting(contentEl).setName("Account");
Object.entries(pluginData.expenseAccounts).forEach(
([key, value]: [string, { icon: string; name: string }]) => {
accountSetting.addButton((btn: ButtonComponent) =>
btn
.setButtonText(key)
.setIcon(value.icon)
.setTooltip(value.name)
.onClick(() => {
this.expenseAccount = value.name;
new Notice(`Selected Account: ${value.name}`);
btn.setCta();
})
);
}
);
const valueSetting = new Setting(contentEl).setName("Value");
Object.entries(pluginData.expenseValues).forEach(
([key, value]: [string, { icon: string; name: string }]) => {
valueSetting.addButton((btn: ButtonComponent) =>
btn
.setButtonText(key)
.setIcon(value.icon)
.setTooltip(value.name)
.onClick(() => {
this.expenseValue = value.name;
new Notice(`Selected Value: ${value.name}`);
btn.setCta();
})
);
}
);
new Setting(contentEl).addButton((btn) =>
btn
.setButtonText("Submit")
.setCta()
.onClick(() => {
this.close();
this.onSubmit(
this.expenseAmount,
this.expenseCategory,
this.expenseAccount,
this.expenseValue
);
const file = this.app.workspace.getActiveFile();
if (file) {
console.log("Debug: active file", file.basename);
const editor =
this.app.workspace.getActiveViewOfType(
MarkdownView
);
if (editor) {
console.log("Debug: active editor", editor);
// get today date and format YYYY-MM-DD
const today = new Date();
const todayFormatted = today
.toISOString()
.split("T")[0];
// move the cursor on start of line 3
editor.editor.setCursor(2, 0);
// insert the new expense on line 3
editor.editor.replaceSelection(
`| ${todayFormatted} | ${formatter.format(
Number(this.expenseAmount)
)} | ${this.expenseCategory} | ${
this.expenseAccount
} | ${this.expenseValue} | \n`
);
}
} else {
console.log("Debug: no active file");
}
})
);
}
onClose() {
const { contentEl } = this;
contentEl.empty();
}
}
class ExpenseSettingTab extends PluginSettingTab { class ExpenseSettingTab extends PluginSettingTab {
plugin: budgetPlugin; plugin: budgetPlugin;