initial commit
This commit is contained in:
		
							
								
								
									
										36
									
								
								app/config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								app/config.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
const fs = require('fs-extra');
 | 
			
		||||
const path = require('path');
 | 
			
		||||
const { app } = require('electron');
 | 
			
		||||
const userDataPath = app.getPath('userData');
 | 
			
		||||
const CONFIG_FILE_NAME = 'timesheet-config.json';
 | 
			
		||||
const configPath = path.join(userDataPath, CONFIG_FILE_NAME);
 | 
			
		||||
 | 
			
		||||
function initializeConfig() {
 | 
			
		||||
  const initial = require('./config.json');
 | 
			
		||||
  saveConfig(initial);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function saveConfig(config) {
 | 
			
		||||
  console.log('Saving: ' + JSON.stringify(config));
 | 
			
		||||
  fs.writeJSONSync(configPath, config, {
 | 
			
		||||
    encoding: 'utf-8',
 | 
			
		||||
    spaces: 2
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function getConfig() {
 | 
			
		||||
  if (!fs.existsSync(configPath)) {
 | 
			
		||||
    initializeConfig();
 | 
			
		||||
  }
 | 
			
		||||
  const options = fs.readJSONSync(configPath, 'utf-8');
 | 
			
		||||
  return options;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function setConfig(config) {
 | 
			
		||||
  saveConfig(config);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  getConfig,
 | 
			
		||||
  setConfig
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										6
									
								
								app/config.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								app/config.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,6 @@
 | 
			
		||||
{
 | 
			
		||||
  "secondsToReload": 60,
 | 
			
		||||
  "cutDay": 6,
 | 
			
		||||
  "cutHour": 4,
 | 
			
		||||
  "timezone": "America/Denver"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										18
									
								
								app/dist/index.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								app/dist/index.html
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,18 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
 | 
			
		||||
<head>
 | 
			
		||||
  <meta charset="UTF-8" />
 | 
			
		||||
  <link rel="icon" type="image/svg+xml" href="./vite.svg" />
 | 
			
		||||
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 | 
			
		||||
  <title>Salud y Vida PA | Timesheet - 1.5.0</title>
 | 
			
		||||
  <script type="module" crossorigin src="./assets/index.680f16a8.js"></script>
 | 
			
		||||
  <link rel="stylesheet" href="./assets/index.6a5e126f.css">
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
  <div id="app"></div>
 | 
			
		||||
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										1
									
								
								app/dist/vite.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								app/dist/vite.svg
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
 | 
			
		||||
| 
		 After Width: | Height: | Size: 1.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								app/favicon-32x32.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								app/favicon-32x32.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 2.3 KiB  | 
							
								
								
									
										33
									
								
								app/index.htm_
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								app/index.htm_
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html lang="en">
 | 
			
		||||
 | 
			
		||||
<head>
 | 
			
		||||
    <meta charset="UTF-8">
 | 
			
		||||
    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline'; connect-src *;">
 | 
			
		||||
    <meta name="viewport" content="width=device-width,initial-scale=1">
 | 
			
		||||
    <title>Fire Sale</title>
 | 
			
		||||
    <link rel="stylesheet" href="style.css" type="text/css">
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
 | 
			
		||||
    <section class="controls">
 | 
			
		||||
        <button id="new-file">New File</button>
 | 
			
		||||
        <button id="open-file">Open File</button>
 | 
			
		||||
        <button id="save-markdown" disabled>Save File</button>
 | 
			
		||||
        <button id="revert" disabled>Revert</button>
 | 
			
		||||
        <button id="save-html">Save HTML</button>
 | 
			
		||||
        <button id="show-file" disabled>Show File</button>
 | 
			
		||||
        <button id="open-in-default" disabled>Open in Default Application</button>
 | 
			
		||||
    </section>
 | 
			
		||||
 | 
			
		||||
    <section class="content">
 | 
			
		||||
        <label for="markdown" hidden>Markdown Content</label>
 | 
			
		||||
        <textarea class="raw-markdown" id="markdown"></textarea>
 | 
			
		||||
        <div class="rendered-html" id="html"></div>
 | 
			
		||||
    </section>
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
<script src="./renderer.js"></script>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										34
									
								
								app/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								app/index.html
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
 | 
			
		||||
<head>
 | 
			
		||||
    <meta charset="UTF-8" />
 | 
			
		||||
    <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'" />
 | 
			
		||||
    <meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'" />
 | 
			
		||||
    <title>Hello from Electron renderer!</title>
 | 
			
		||||
    <link rel="stylesheet" href="style.css" type="text/css">
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
    <h1>Hello from Electron renderer!</h1>
 | 
			
		||||
    <p>👋</p>
 | 
			
		||||
    <p id="info"></p>
 | 
			
		||||
    <section class="controls">
 | 
			
		||||
        <button id="new-file">New File</button>
 | 
			
		||||
        <button id="open-file">Open File</button>
 | 
			
		||||
        <button id="save-markdown" disabled>Save File</button>
 | 
			
		||||
        <button id="revert" disabled>Revert</button>
 | 
			
		||||
        <button id="save-html">Save HTML</button>
 | 
			
		||||
        <button id="show-file" disabled>Show File</button>
 | 
			
		||||
        <button id="open-in-default" disabled>Open in Default Application</button>
 | 
			
		||||
    </section>
 | 
			
		||||
 | 
			
		||||
    <section class="content">
 | 
			
		||||
        <label for="markdown" hidden>Markdown Content</label>
 | 
			
		||||
        <textarea class="raw-markdown" id="markdown"></textarea>
 | 
			
		||||
        <div class="rendered-html" id="html"></div>
 | 
			
		||||
    </section>
 | 
			
		||||
</body>
 | 
			
		||||
<script src="./renderer.js"></script>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										57
									
								
								app/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								app/main.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,57 @@
 | 
			
		||||
const { app, BrowserWindow, ipcMain } = require('electron');
 | 
			
		||||
const path = require('path');
 | 
			
		||||
const { post } = require('./request')
 | 
			
		||||
const { deputyUrl, deputyToken } = require('../env.json');
 | 
			
		||||
const { getConfig, setConfig } = require('./config');
 | 
			
		||||
 | 
			
		||||
function createWindow() {
 | 
			
		||||
  const mainWindow = new BrowserWindow({
 | 
			
		||||
    width: 1440 ,
 | 
			
		||||
    height: 900,
 | 
			
		||||
    show: false,
 | 
			
		||||
    icon: path.join(__dirname, 'favicon-32x32.png'),
 | 
			
		||||
    webPreferences: {
 | 
			
		||||
      preload: path.join(__dirname, 'preload.js'),
 | 
			
		||||
      allowRunningInsecureContent: true,
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  ipcMain.handle('getTimesheet', async(event, body) => {
 | 
			
		||||
    try {
 | 
			
		||||
      const { apitoken } = getConfig();
 | 
			
		||||
      const token = apitoken || deputyToken;
 | 
			
		||||
      return await post(deputyUrl, body, { Authorization: `OAuth ${token}` });
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      console.log('err :>> ', err);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  ipcMain.handle('getAppConfig', () => {
 | 
			
		||||
    const config = getConfig();
 | 
			
		||||
    return {... { apitoken: deputyToken }, ...config };
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  ipcMain.handle('setAppConfig', (event, config) => {
 | 
			
		||||
    return setConfig(config);
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  mainWindow.maximize();
 | 
			
		||||
  mainWindow.removeMenu();
 | 
			
		||||
  mainWindow.loadFile(path.join(__dirname, '..', 'ui', 'dist', 'index.html'));
 | 
			
		||||
 | 
			
		||||
  // Open the DevTools.
 | 
			
		||||
  // mainWindow.webContents.openDevTools();
 | 
			
		||||
  mainWindow.show();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
app.whenReady().then(() => {
 | 
			
		||||
  createWindow();
 | 
			
		||||
 | 
			
		||||
  app.on('activate', () => {
 | 
			
		||||
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
 | 
			
		||||
  })
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
app.on('window-all-closed', function() {
 | 
			
		||||
  if (process.platform !== 'darwin') app.quit()
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										16
									
								
								app/preload.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								app/preload.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
const { contextBridge, ipcRenderer } = require('electron');
 | 
			
		||||
 | 
			
		||||
contextBridge.exposeInMainWorld('IS_ELECTRON', true);
 | 
			
		||||
 | 
			
		||||
contextBridge.exposeInMainWorld('versions', {
 | 
			
		||||
  node: () => process.versions.node,
 | 
			
		||||
  chrome: () => process.versions.chrome,
 | 
			
		||||
  electron: () => process.versions.electron,
 | 
			
		||||
  app: () => '1.2.2',
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
contextBridge.exposeInMainWorld('services', {
 | 
			
		||||
  getTimesheet: (body) => ipcRenderer.invoke('getTimesheet', body),
 | 
			
		||||
  getConfig: () => ipcRenderer.invoke('getAppConfig'),
 | 
			
		||||
  setConfig: config => ipcRenderer.invoke('setAppConfig', config),
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										7
									
								
								app/renderer.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								app/renderer.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,7 @@
 | 
			
		||||
const func = async() => {
 | 
			
		||||
  const response = window.versions.app
 | 
			
		||||
  console.log(response);
 | 
			
		||||
  window.title += ` ${window.versions.app}`;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func();
 | 
			
		||||
							
								
								
									
										64
									
								
								app/request.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								app/request.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,64 @@
 | 
			
		||||
const { net } = require('electron');
 | 
			
		||||
 | 
			
		||||
async function get(url, headers) {
 | 
			
		||||
  return request({ url, method: 'GET', headers })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function post(url, body, headers) {
 | 
			
		||||
  return request({ url, method: 'POST', headers }, body)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async function request(options, body) {
 | 
			
		||||
 | 
			
		||||
  return new Promise((resolve, reject) => {
 | 
			
		||||
    const responseBody = [];
 | 
			
		||||
    let responseHeaders;
 | 
			
		||||
    let responseStatus;
 | 
			
		||||
 | 
			
		||||
    const request = net.request(options);
 | 
			
		||||
 | 
			
		||||
    request.on('response', (response) => {
 | 
			
		||||
      responseStatus = response.statusCode;
 | 
			
		||||
      responseHeaders = response.headers;
 | 
			
		||||
 | 
			
		||||
      response.on('data', (chunk) => {
 | 
			
		||||
        if (chunk) {
 | 
			
		||||
          responseBody.push(`${chunk}`);
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
      response.on('end', () => {
 | 
			
		||||
        resolve({
 | 
			
		||||
          status: responseStatus,
 | 
			
		||||
          headers: responseHeaders,
 | 
			
		||||
          body: parseReponseBody(responseBody),
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
      response.on('aborted', () => console.log('request aborted'));
 | 
			
		||||
      response.on('error', (error) => reject(error));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    request.on('error', (error) => reject(error));
 | 
			
		||||
 | 
			
		||||
    request.setHeader('Content-Type', 'application/json');
 | 
			
		||||
    if (['POST'].includes(options.method.toUpperCase())) {
 | 
			
		||||
      request.write(JSON.stringify(body), 'utf-8')
 | 
			
		||||
    }
 | 
			
		||||
    request.end();
 | 
			
		||||
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function parseReponseBody(body) {
 | 
			
		||||
  if (Array.isArray(body)) {
 | 
			
		||||
    if (body.length) {
 | 
			
		||||
      return JSON.parse(body.join(''));
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
module.exports = {
 | 
			
		||||
  get,
 | 
			
		||||
  post
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										99
									
								
								app/style.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								app/style.css
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,99 @@
 | 
			
		||||
html {
 | 
			
		||||
    box-sizing: border-box;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
*,
 | 
			
		||||
*:before,
 | 
			
		||||
*:after {
 | 
			
		||||
    box-sizing: inherit;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
html,
 | 
			
		||||
body {
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
body {
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    padding: 0;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
body,
 | 
			
		||||
input {
 | 
			
		||||
    font: menu;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
textarea,
 | 
			
		||||
input,
 | 
			
		||||
div,
 | 
			
		||||
button {
 | 
			
		||||
    outline: none;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.controls {
 | 
			
		||||
    background-color: rgb(217, 241, 238);
 | 
			
		||||
    padding: 10px 10px 10px 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
button {
 | 
			
		||||
    font-size: 14px;
 | 
			
		||||
    background-color: rgb(181, 220, 216);
 | 
			
		||||
    border: none;
 | 
			
		||||
    padding: 0.5em 1em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
button:hover {
 | 
			
		||||
    background-color: rgb(156, 198, 192);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
button:active {
 | 
			
		||||
    background-color: rgb(144, 182, 177);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
button:disabled {
 | 
			
		||||
    background-color: rgb(196, 204, 202);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.container {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-direction: column;
 | 
			
		||||
    min-height: 100vh;
 | 
			
		||||
    min-width: 100vw;
 | 
			
		||||
    position: relative;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.content {
 | 
			
		||||
    height: 100vh;
 | 
			
		||||
    display: flex;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.raw-markdown,
 | 
			
		||||
.rendered-html {
 | 
			
		||||
    min-height: 100%;
 | 
			
		||||
    max-width: 50%;
 | 
			
		||||
    flex-grow: 1;
 | 
			
		||||
    padding: 1em;
 | 
			
		||||
    overflow: scroll;
 | 
			
		||||
    font-size: 16px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.raw-markdown {
 | 
			
		||||
    border: 5px solid rgb(238, 252, 250);
 | 
			
		||||
    ;
 | 
			
		||||
    background-color: rgb(238, 252, 250);
 | 
			
		||||
    font-family: monospace;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.raw-markdown.drag-over {
 | 
			
		||||
    background-color: rgb(181, 220, 216);
 | 
			
		||||
    border-color: rgb(75, 160, 151);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.raw-markdown.drag-error {
 | 
			
		||||
    background-color: rgba(170, 57, 57, 1);
 | 
			
		||||
    border-color: rgba(255, 170, 170, 1);
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user