Skip to content

Commit

Permalink
store link scores state
Browse files Browse the repository at this point in the history
  • Loading branch information
j4w3ny committed Jun 22, 2022
1 parent 7d6e4cc commit 66949a3
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 35 deletions.
2 changes: 2 additions & 0 deletions app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"@types/react-dom": "^18.0.0",
"axios": "^0.27.2",
"dayjs": "^1.11.3",
"lodash": "^4.17.21",
"react": "^18.1.0",
"react-dom": "^18.1.0",
"react-hook-form": "^7.31.3",
Expand Down Expand Up @@ -52,6 +53,7 @@
},
"devDependencies": {
"@craco/craco": "^6.4.3",
"@types/lodash": "^4.14.182",
"craco-swc": "^0.5.1"
}
}
129 changes: 97 additions & 32 deletions app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ import {
ArrowUpward,
CalendarMonth,
FormatListBulleted,
LooksOne,
SortByAlpha,
} from '@mui/icons-material';
import { intersection } from 'lodash';

interface LinkInfo {
title: string;
Expand Down Expand Up @@ -59,33 +60,39 @@ interface OpenGraph {
/// Represents the "og:locale" OpenGraph meta tag
locale: string;
}
interface Config {
mode: SortMode;
score: string[];
}
interface LinkListItemProps {
link: LinkInfo;
index: number;
}
type SortMode = 'normal' | 'date' | 'score';
const Home = () => {
const [mode, setMode] = useState<SortMode>('normal');
const [, setLinkNames] = useState<string[]>([]);

const [linkInfos, setLinkInfos] = useState<LinkInfo[]>([]);
const { register, handleSubmit, reset } = useForm<LinkInfo>();

const [page, setPage] = useState(0);
console.log(linkInfos);
const itemPerPage = 5;
const pageCount = Math.ceil(linkInfos.length / itemPerPage);

const createLink: SubmitHandler<LinkInfo> = (data) => {
invoke('create_link', {
...data,
}).then(() => {
// Forced refreash view to ensure updated list.
refreshInfo();
toast('Link created!');
reset();
});
};

// Refresh all info.
const refreshInfo = useCallback(async () => {
const names = (await invoke('read_link_list')) as string[];
setLinkNames(names);

const links = await Promise.all(
names.map(async (val) => {
const link = {
Expand All @@ -95,7 +102,48 @@ const Home = () => {
} as LinkInfo;
return link;
})
);
).catch((e) => {
console.error(e);
throw e;
});

const defaultConfig: Config = {
mode: 'score',
score: links.map((val) => val.name),
};
// Get config or initialize one.
const initialConfig = await invoke<Config>('get_config').catch((e) => {
console.log('failed to get config', e);
// Fallback to create the default config
return invoke<Config>('set_config', {
config: defaultConfig,
});
});

console.log('initialConfig:', initialConfig);
// Merge List item into config score when mode is set to score.
if (mode === 'score') {
// merge config score with current linkList
//
// if a item is added/deleted from disk, it will disappeared on the list.
let mergedScore = intersection(
initialConfig.score,
links.map((val) => val.name)
);
console.log('merged:', mergedScore);
console.log('links', links);
let mergedLinkInfos = mergedScore.map((val) => {
const link = links.find((link) => {
return link.name === val;
});
return link;
}) as LinkInfo[];

console.log('mergedLinkInfos:', mergedLinkInfos);
setLinkInfos(mergedLinkInfos);
return;
}
// Sort and push link infos
setLinkInfos(
(links as LinkInfo[])
// eslint-disable-next-line array-callback-return
Expand All @@ -109,25 +157,35 @@ const Home = () => {
a.created_time.secs_since_epoch
);
// Default to score
case 'score':
return 0;
}
})
// TODO
);
}, [mode]);

useEffect(() => {
refreshInfo();
}, [refreshInfo]);
interface LinkListProps {
linkInfos: LinkInfo[];
}
const LinkList = ({ linkInfos }: LinkListProps) => {
const [scoreLinkInfos, setScoreLinkInfos] = useState<LinkInfo[]>(linkInfos);

const updateScore = (arr: LinkInfo[]) => {
const updatedConfig: Config = {
mode: 'score',
score: arr.map((val) => val.name),
};
console.log('updatedConfig:', updatedConfig);
invoke('set_config', {
config: updatedConfig,
})
.then((_) => {
console.log('successfully set config');
})
.catch((e) => {
throw e;
});
};
const LinkList = () => {
const LinkListItem = ({ link, index }: LinkListItemProps) => {
const [previewInfo, setPreviewInfo] = useState<OpenGraph>();

useEffect(() => {
invoke('generate_link_preview', {
url: link.url.toString(),
Expand Down Expand Up @@ -181,8 +239,6 @@ const Home = () => {
}}>
{'COPY'}
</Button>
{/* </Grid>
<Grid item m='auto' p='auto'> */}
<Button
onClick={() => {
open(link.url.toString());
Expand All @@ -200,25 +256,28 @@ const Home = () => {
color='error'>
DELETE
</Button>

<IconButton
color='primary'
disabled={index === 0}
disabled={index === 0 || mode !== 'score'}
onClick={() => {
let arr = Array.from(scoreLinkInfos);
let arr = Array.from(linkInfos);
[arr[index - 1], arr[index]] = [arr[index], arr[index - 1]];
console.log(arr);
setScoreLinkInfos(arr);
setLinkInfos(arr);
updateScore(arr);
}}>
<ArrowUpward />
</IconButton>
<IconButton
color='error'
disabled={index === linkInfos.length - 1}
disabled={index === linkInfos.length - 1 || mode !== 'score'}
onClick={() => {
let arr = Array.from(scoreLinkInfos);
let arr = Array.from(linkInfos);
[arr[index], arr[index + 1]] = [arr[index + 1], arr[index]];
console.log(arr);
setScoreLinkInfos(arr);
setLinkInfos(arr);
updateScore(arr);
}}>
<ArrowDownward />
</IconButton>
Expand All @@ -230,7 +289,7 @@ const Home = () => {
};
return (
<List>
{scoreLinkInfos
{linkInfos
.map((val, idx) => {
return (
<div id={val.title} key={val.title}>
Expand Down Expand Up @@ -265,7 +324,7 @@ const Home = () => {
<Grid item xs={8}>
<Card>
<CardContent>
<LinkList linkInfos={linkInfos} />
<LinkList />

<Pagination
count={pageCount === 0 ? 1 : pageCount}
Expand All @@ -282,24 +341,30 @@ const Home = () => {
</Grid>
<Grid item xs={4}>
<Grid item>
<ButtonGroup>
<Tooltip title={'Normal mode'}>
<ButtonGroup variant='outlined'>
<Tooltip key='alphabet' title={'Sorting By Alphabet'}>
<IconButton
onClick={() => {
setMode('normal');
}}>
<FormatListBulleted />
<SortByAlpha />
</IconButton>
</Tooltip>

<Tooltip title={'Sorting By Date'}>
<IconButton onClick={() => setMode('date')}>
<Tooltip key='date' title={'Sorting By Date'}>
<IconButton
onClick={() => {
setMode('date');
}}>
<CalendarMonth />
</IconButton>
</Tooltip>
<Tooltip title={'Sorting By Score'}>
<IconButton onClick={() => setMode('score')}>
<LooksOne />
<Tooltip key='score' title={'Sorting By Score'}>
<IconButton
onClick={() => {
setMode('score');
}}>
<FormatListBulleted />
</IconButton>
</Tooltip>
</ButtonGroup>
Expand Down
20 changes: 20 additions & 0 deletions core/src/base/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,22 @@
mod link;
pub use link::{Link, OpenGraph};
use serde::{Deserialize, Serialize};
/// ARK Config
#[derive(Debug, Serialize, Deserialize)]
pub struct Config {
/// Sorting mode.
pub mode: Mode,
/// The score content, repensented to a score.
pub score: Option<Vec<String>>,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Mode {
/// Sorting by Alphabet
Normal,
/// Sorting by date
Date,
/// Sorting by score
Score,
}
29 changes: 26 additions & 3 deletions core/src/command/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
use std::{fs, path::PathBuf};
use std::{
fs::{self, File},
io::Write,
path::PathBuf,
};

use crate::{
base::{Link, OpenGraph},
base::{Config, Link, OpenGraph},
Cli,
};

Expand Down Expand Up @@ -52,6 +56,23 @@ async fn generate_link_preview(url: String) -> Result<OpenGraph, String> {
Link::get_preview(url).await.map_err(|e| e.to_string())
}

#[tauri::command(async)]
fn get_config(state: tauri::State<Cli>) -> Result<Config, String> {
let config_path = PathBuf::from(&state.path).join("ark_config");
let file = File::open(config_path).map_err(|e| e.to_string())?;
let j = serde_json::from_reader(file).map_err(|e| e.to_string())?;
Ok(j)
}

#[tauri::command(async)]
fn set_config(config: Config, state: tauri::State<Cli>) -> Result<(), String> {
let config_path = PathBuf::from(&state.path).join("ark_config");
let mut file = File::create(config_path).map_err(|e| e.to_string())?;
file.write_all(serde_json::to_vec(&config).unwrap().as_slice())
.map_err(|e| e.to_string())?;
Ok(())
}

#[tauri::command(async)]
/// Read data from `.link` file
fn read_link(name: String, state: tauri::State<Cli>) -> Link {
Expand All @@ -63,9 +84,11 @@ fn read_link(name: String, state: tauri::State<Cli>) -> Link {
pub fn set_command<R: Runtime>(builder: Builder<R>) -> Builder<R> {
builder.invoke_handler(tauri::generate_handler![
create_link,
read_link,
read_link_list,
delete_link,
generate_link_preview,
read_link,
get_config,
set_config
])
}
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2409,6 +2409,11 @@
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==

"@types/lodash@^4.14.182":
version "4.14.182"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.182.tgz#05301a4d5e62963227eaafe0ce04dd77c54ea5c2"
integrity sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==

"@types/mime@^1":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a"
Expand Down

0 comments on commit 66949a3

Please sign in to comment.