chore: update to so many things

This commit is contained in:
Andre Henriques 2024-10-13 11:37:19 +01:00
parent 5253204e17
commit 5380eaffeb
10 changed files with 410 additions and 145 deletions

View File

@ -1,11 +1,12 @@
package com.andr3h3nriqu3s.applications package com.andr3h3nriqu3s.applications
import java.sql.ResultSet import java.sql.ResultSet
import java.util.UUID
import java.util.Date
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date
import java.util.UUID
import kotlin.collections.emptyList import kotlin.collections.emptyList
import kotlin.collections.setOf import kotlin.collections.setOf
import org.springframework.http.HttpStatus
import org.springframework.http.MediaType import org.springframework.http.MediaType
import org.springframework.jdbc.core.JdbcTemplate import org.springframework.jdbc.core.JdbcTemplate
import org.springframework.jdbc.core.RowMapper import org.springframework.jdbc.core.RowMapper
@ -20,6 +21,7 @@ import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestHeader import org.springframework.web.bind.annotation.RequestHeader
import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController import org.springframework.web.bind.annotation.RestController
import org.springframework.web.server.ResponseStatusException
data class Application( data class Application(
var id: String, var id: String,
@ -37,6 +39,7 @@ data class Application(
var linked_application: String, var linked_application: String,
var status_history: String, var status_history: String,
var application_time: String, var application_time: String,
var create_time: String,
var flairs: List<Flair>, var flairs: List<Flair>,
var views: List<View>, var views: List<View>,
) { ) {
@ -58,6 +61,7 @@ data class Application(
rs.getString("linked_application"), rs.getString("linked_application"),
rs.getString("status_history"), rs.getString("status_history"),
rs.getString("application_time"), rs.getString("application_time"),
rs.getString("create_time"),
emptyList(), emptyList(),
emptyList(), emptyList(),
) )
@ -109,6 +113,77 @@ class ApplicationsController(
return CVData(application.company, application.recruiter, application.message, flairs) return CVData(application.company, application.recruiter, application.message, flairs)
} }
/** Create a new application from the link */
@PostMapping(path = ["/link"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun submitLink(
@RequestBody submit: SubmitRequest,
@RequestHeader("token") token: String
): Application {
val user = sessionService.verifyTokenThrow(token)
var application =
Application(
UUID.randomUUID().toString(),
submit.text,
submit.text,
submit.text,
"New Application",
user.id,
"",
"",
0,
"",
"",
"",
"",
"",
"",
"",
emptyList(),
emptyList(),
)
if (!applicationService.createApplication(user, application)) {
throw ResponseStatusException(HttpStatus.CONFLICT, "Application already exists", null)
}
print("Created: ")
println(application)
return application
}
@PostMapping(path = ["/text/flair"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun textFlair(
@RequestBody info: FlairRequest,
@RequestHeader("token") token: String
): Int {
val user = sessionService.verifyTokenThrow(token)
val application = applicationService.findApplicationById(user, info.id)
if (application == null) {
throw ResponseStatusException(HttpStatus.NOT_FOUND, "Application not found", null)
}
val flairs = flairService.listUser(user)
var count = 0
for (flair: Flair in flairs) {
val regex =
Regex(
".*" + flair.expr + ".*",
setOf(RegexOption.IGNORE_CASE, RegexOption.DOT_MATCHES_ALL)
)
if (regex.matches(info.text)) {
count += 1
flairService.linkFlair(application, flair)
}
}
return count
}
@PostMapping(path = ["/text"], produces = [MediaType.APPLICATION_JSON_VALUE]) @PostMapping(path = ["/text"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun submitText( public fun submitText(
@RequestBody submit: SubmitRequest, @RequestBody submit: SubmitRequest,
@ -179,7 +254,7 @@ class ApplicationsController(
if (elm.contains("linkedin")) elm.split("?")[0] else elm, if (elm.contains("linkedin")) elm.split("?")[0] else elm,
if (elm.contains("linkedin")) elm.split("?")[0] else null, if (elm.contains("linkedin")) elm.split("?")[0] else null,
if (elm.contains("linkedin")) elm.split("?")[0] else null, if (elm.contains("linkedin")) elm.split("?")[0] else null,
"New Aplication", "New Application",
user.id, user.id,
"", "",
"", "",
@ -190,6 +265,7 @@ class ApplicationsController(
"", "",
"", "",
"", "",
"",
emptyList(), emptyList(),
emptyList(), emptyList(),
) )
@ -205,37 +281,6 @@ class ApplicationsController(
return applications.size return applications.size
} }
@PostMapping(path = ["/text/flair"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun textFlair(
@RequestBody info: FlairRequest,
@RequestHeader("token") token: String
): Int {
val user = sessionService.verifyTokenThrow(token)
val application = applicationService.findApplicationById(user, info.id)
if (application == null) {
throw NotFound()
}
val flairs = flairService.listUser(user)
var count = 0
for (flair: Flair in flairs) {
val regex =
Regex(
".*" + flair.expr + ".*",
setOf(RegexOption.IGNORE_CASE, RegexOption.DOT_MATCHES_ALL)
)
if (regex.matches(info.text)) {
count += 1
flairService.linkFlair(application, flair)
}
}
return count
}
@PostMapping(path = ["/list"], produces = [MediaType.APPLICATION_JSON_VALUE]) @PostMapping(path = ["/list"], produces = [MediaType.APPLICATION_JSON_VALUE])
public fun list( public fun list(
@RequestBody info: ListRequest, @RequestBody info: ListRequest,
@ -267,10 +312,10 @@ class ApplicationsController(
} }
application.status = info.status application.status = info.status
val status_string = "${info.status}"; val status_string = "${info.status}"
var status_history = application.status_history.split(",").filter { it.length >= 1 } var status_history = application.status_history.split(",").filter { it.length >= 1 }
if (status_history.indexOf(status_string) == -1) { if (status_history.indexOf(status_string) == -1) {
status_history = status_history.plus("${info.status}"); status_history = status_history.plus("${info.status}")
} }
application.status_history = status_history.joinToString(",") { it } application.status_history = status_history.joinToString(",") { it }
@ -308,11 +353,11 @@ class ApplicationsController(
var application = applicationService.findApplicationById(user, info.id) var application = applicationService.findApplicationById(user, info.id)
if (application == null) { if (application == null) {
throw NotFound() throw ResponseStatusException(HttpStatus.NOT_FOUND, "Application not found", null)
} }
if (application.unique_url != null) { if (application.unique_url != null) {
throw BadRequest() throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Application already has unique_url", null)
} }
application.original_url = application.url application.original_url = application.url
@ -341,6 +386,7 @@ class ApplicationsController(
applicationService.update(application) applicationService.update(application)
application.flairs = flairService.listFromLinkApplicationId(application.id) application.flairs = flairService.listFromLinkApplicationId(application.id)
application.views = viewService.listFromApplicationId(application.id)
return application return application
} }
@ -485,6 +531,7 @@ class ApplicationService(
return false return false
} }
// Create time is auto created by the database
db.update( db.update(
"insert into applications (id, url, original_url, unique_url, title, user_id, extra_data, payrange, status, company, recruiter, message, linked_application, status_history, application_time) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", "insert into applications (id, url, original_url, unique_url, title, user_id, extra_data, payrange, status, company, recruiter, message, linked_application, status_history, application_time) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);",
application.id, application.id,
@ -527,7 +574,6 @@ class ApplicationService(
.toList() .toList()
} }
return db.query( return db.query(
"select * from applications where user_id=? and status=? order by title asc;", "select * from applications where user_id=? and status=? order by title asc;",
arrayOf(user.id, info.status), arrayOf(user.id, info.status),
@ -537,6 +583,7 @@ class ApplicationService(
} }
public fun update(application: Application): Application { public fun update(application: Application): Application {
// I don't want ot update create_time
db.update( db.update(
"update applications set url=?, original_url=?, unique_url=?, title=?, user_id=?, extra_data=?, payrange=?, status=?, company=?, recruiter=?, message=?, linked_application=?, status_history=?, application_time=? where id=?", "update applications set url=?, original_url=?, unique_url=?, title=?, user_id=?, extra_data=?, payrange=?, status=?, company=?, recruiter=?, message=?, linked_application=?, status_history=?, application_time=? where id=?",
application.url, application.url,

View File

@ -25,7 +25,8 @@ create table if not exists applications (
extra_data text, extra_data text,
status integer, status integer,
linked_application text default '', linked_application text default '',
application_time text default '' application_time text default '',
create_time timestamp default now()
); );
create table if not exists views ( create table if not exists views (

View File

@ -40,3 +40,5 @@ ## Building
## TODO ## TODO
https://www.glassdoor.co.uk/job-listing/junior-software-developer-full-stack-onnec-group-JV_IC2671300_KO0,36_KE37,48.htm?jl=1009478590946&utm_source=jobsForYou&utm_medium=email&utm_content=jobs-for-you-jobsForYou-jobpos5-1009478590946&utm_campaign=jobsForYou&src=GD_JOB_AD&uido=5EF1E454F911F36A51BB1DD9CB97C8DB&ao=1136043&jrtk=6-y100011i9mkhgisgqqb801ab7157ddf833b2e1c&cs=1_57b69a24&s=362&t=REC_JOBS&pos=105&guid=00000192656d7c18b164f224f0a88e83&jobListingId=1009478590946&ea=1&vt=e&cb=1728410338190&ctt=1728466768707 https://www.glassdoor.co.uk/job-listing/junior-software-developer-full-stack-onnec-group-JV_IC2671300_KO0,36_KE37,48.htm?jl=1009478590946&utm_source=jobsForYou&utm_medium=email&utm_content=jobs-for-you-jobsForYou-jobpos5-1009478590946&utm_campaign=jobsForYou&src=GD_JOB_AD&uido=5EF1E454F911F36A51BB1DD9CB97C8DB&ao=1136043&jrtk=6-y100011i9mkhgisgqqb801ab7157ddf833b2e1c&cs=1_57b69a24&s=362&t=REC_JOBS&pos=105&guid=00000192656d7c18b164f224f0a88e83&jobListingId=1009478590946&ea=1&vt=e&cb=1728410338190&ctt=1728466768707
https://careers.veeva.com/job/866d4776-9d23-4311-ab16-4ebff725984d/frontend-engineer-react-remote-london-united-kingdom/

View File

@ -49,6 +49,8 @@ export type Application = {
message: string; message: string;
linked_application: string; linked_application: string;
application_time: string; application_time: string;
create_time: string;
status_history: string;
flairs: Flair[]; flairs: Flair[];
views: View[]; views: View[];
}; };

View File

@ -150,7 +150,7 @@
<div class="p-3 bg-white w-[190mm] rounded-lg"> <div class="p-3 bg-white w-[190mm] rounded-lg">
<h1 class="flex gap-5 items-end"> <h1 class="flex gap-5 items-end">
Your Ad & My skills {#if flairs.length > 0}<input Your Ad & My skills {#if flairs.length > 0}<input
placeholder="Loking for other skills search?" placeholder="Search other skills!"
class="flex-grow text-blue-500 print:hidden" class="flex-grow text-blue-500 print:hidden"
bind:value={otherSearch} bind:value={otherSearch}
/> />

View File

@ -21,119 +21,125 @@
| AsEnum<typeof ApplicationStatus> | AsEnum<typeof ApplicationStatus>
| 'Linkedin' | 'Linkedin'
| 'Glassdoor' | 'Glassdoor'
| 'Unknown Source' | 'Direct Source';
| 'Applications';
let nodeTypes: Record<NodeType, number> = { let graph = {} as Record<string, Record<string, number>>;
[ApplicationStatus.ToApply]: 0,
[ApplicationStatus.WorkingOnIt]: 0,
[ApplicationStatus.Ignore]: 0,
[ApplicationStatus.ApplyedButSaidNo]: 0,
[ApplicationStatus.Expired]: 0,
[ApplicationStatus.Applyed]: 0,
[ApplicationStatus.TasksToDo]: 0,
[ApplicationStatus.LinkedApplication]: 0,
Linkedin: 0,
Glassdoor: 0,
'Unknown Source': 0,
Applications: applications.length
};
const showPercentage: string[] = [ function addGraph(inSource: NodeType, inTarget: NodeType) {
`${ApplicationStatus.ToApply}`, const source = `${inSource}`;
`${ApplicationStatus.Ignore}`, const target = `${inTarget}`;
`${ApplicationStatus.Expired}`, if (graph[source] == undefined) {
`${ApplicationStatus.Applyed}`, graph[source] = {} as Record<NodeType, number>;
`${ApplicationStatus.LinkedApplication}`, }
`${ApplicationStatus.ApplyedButSaidNo}`, graph[source][target] = (graph[source][target] ?? 0) + 1;
`${ApplicationStatus.TasksToDo}` return target as NodeType;
]; }
const baseLinks: { source: NodeType; target: NodeType; value: 0 | 1; end?: boolean }[] =
[
{ source: 'Linkedin', target: 'Applications', value: 0 },
{ source: 'Glassdoor', target: 'Applications', value: 0 },
{ source: 'Unknown Source', target: 'Applications', value: 0 },
{ source: 'Applications', target: ApplicationStatus.ToApply, value: 1 },
{ source: 'Applications', target: ApplicationStatus.Ignore, value: 1 },
{ source: 'Applications', target: ApplicationStatus.Expired, value: 1 },
{ source: 'Applications', target: ApplicationStatus.Applyed, value: 1 },
{
source: 'Applications',
target: ApplicationStatus.LinkedApplication,
value: 1
},
{
source: ApplicationStatus.Applyed,
target: ApplicationStatus.ApplyedButSaidNo,
value: 1
},
{
source: ApplicationStatus.Applyed,
target: ApplicationStatus.TasksToDo,
value: 1
}
];
applications.forEach((a) => { applications.forEach((a) => {
let source: NodeType;
if (a.url.includes('linkedin')) { if (a.url.includes('linkedin')) {
nodeTypes['Linkedin'] += 1; source = 'Linkedin';
} else if (a.url.includes('glassdoor')) { } else if (a.url.includes('glassdoor')) {
nodeTypes['Glassdoor'] += 1; source = 'Glassdoor';
} else { } else {
nodeTypes['Unknown Source'] += 1; source = 'Direct Source';
}
if (a.status !== ApplicationStatus.WorkingOnIt) {
nodeTypes[a.status] += 1;
} else {
nodeTypes[ApplicationStatus.ToApply] += 1;
} }
if ( if (
[ApplicationStatus.ApplyedButSaidNo, ApplicationStatus.TasksToDo].includes( (
[
ApplicationStatus.Ignore,
ApplicationStatus.Expired,
ApplicationStatus.LinkedApplication,
ApplicationStatus.ToApply,
ApplicationStatus.Applyed
] as AsEnum<typeof ApplicationStatus>[]
).includes(a.status)
) {
addGraph(source, a.status);
return;
}
// Edge case for working on it
if (a.status === ApplicationStatus.WorkingOnIt) {
addGraph(source, ApplicationStatus.ToApply);
return;
}
if (a.status == ApplicationStatus.ApplyedButSaidNo) {
const history = a.status_history.split(',');
source = addGraph(source, ApplicationStatus.Applyed);
if (history.includes(`${ApplicationStatus.TasksToDo}`)) {
source = addGraph(source, ApplicationStatus.TasksToDo);
}
addGraph(source, ApplicationStatus.ApplyedButSaidNo);
} else if (
([ApplicationStatus.TasksToDo] as AsEnum<typeof ApplicationStatus>[]).includes(
a.status a.status
) )
) { ) {
nodeTypes[ApplicationStatus.Applyed] += 1; addGraph(source, ApplicationStatus.Applyed);
addGraph(ApplicationStatus.Applyed, a.status);
} }
}); });
let inNodes: string[] = []; let inNodes: string[] = Object.keys(graph).reduce((acc, elm) => {
const arr = Object.keys(graph[elm]).concat(elm);
let nodes = (Object.keys(nodeTypes) as (keyof typeof nodeTypes)[]) for (const i of arr) {
.filter((a) => nodeTypes[a] > 0) if (!acc.includes(i)) {
.map((a, i) => { acc.push(i);
inNodes.push(`${a}`);
const base = {
value: nodeTypes[a],
originalValue: a,
id: '',
index: i,
percentage: Math.trunc((nodeTypes[a] / applications.length) * 100),
end: showPercentage.includes(`${a}`)
};
if (Number.isNaN(Number(a))) {
base.id = a as string;
} else {
base.id = ApplicationStatusMaping[a as AsEnum<typeof ApplicationStatus>];
} }
return base; }
}); return acc;
}, [] as string[]);
const links = baseLinks function getGraphValueFor(node: string): number {
.filter( return Object.keys(graph).reduce((acc, i) => {
(link) => if (i == node) return acc;
inNodes.includes(`${link.source}`) && inNodes.includes(`${link.target}`) if (graph[i][node] != undefined) {
) return acc + graph[i][node];
.map((link) => { }
const source = inNodes.indexOf(`${link.source}`); return acc;
const target = inNodes.indexOf(`${link.target}`); }, 0);
return { }
source: source,
target: target, let nodes = inNodes.map((node, i) => {
value: [nodes[source], nodes[target]][link.value].value let name = '';
}; if (Number.isNaN(Number(node))) {
}); name = node;
} else {
name = ApplicationStatusMaping[Number(node) as AsEnum<typeof ApplicationStatus>];
}
const value = getGraphValueFor(node);
const base = {
value: value,
originalValue: node,
id: name,
index: i,
percentage: Math.trunc((value / applications.length) * 100),
end: true
};
return base;
});
type Link = {
source: number;
target: number;
value: number;
}
const links = Object.keys(graph).reduce((acc, source) => {
return acc.concat(Object.keys(graph[source]).map((target) => {
const ns = inNodes.indexOf(`${source}`);
const nt = inNodes.indexOf(`${target}`);
return {
source: ns,
target: nt,
value: graph[source][target]
};
}));
}, [] as Link[])
const bounding = chartDiv.getBoundingClientRect(); const bounding = chartDiv.getBoundingClientRect();
@ -146,6 +152,8 @@
sankey.nodes(nodes).links(links).layout(32); sankey.nodes(nodes).links(links).layout(32);
console.log("here2", nodes, links);
const svg = d3 const svg = d3
.select(chartDiv) .select(chartDiv)
.append('svg') .append('svg')
@ -171,6 +179,9 @@
.append('path') .append('path')
.attr('class', 'link') .attr('class', 'link')
.attr('d', path) .attr('d', path)
.style('stroke', function(d) {
return d3.rgb(color[d.source.index]).toString();
})
.style('stroke-width', function (d) { .style('stroke-width', function (d) {
return Math.max(1, d.dy); return Math.max(1, d.dy);
}) })
@ -269,7 +280,6 @@
:global(.link) { :global(.link) {
fill: none; fill: none;
stroke: #000; stroke-opacity: 0.5;
stroke-opacity: 0.2;
} }
</style> </style>

View File

@ -0,0 +1,51 @@
<script lang="ts">
import type { Application } from '$lib/ApplicationsStore.svelte';
import { post, preventDefault } from '$lib/utils';
let {
onreload
}: {
onreload: (item: Application) => void;
} = $props();
let dialogElement: HTMLDialogElement;
let link = $state('');
async function createApplication() {
try {
const r: Application = await post('application/link', {
text: link
});
onreload(r);
dialogElement.close()
} catch (e) {
console.log('Inform the user', e);
}
}
function docKey(e: KeyboardEvent) {
if (e.ctrlKey && e.code === 'KeyN') {
dialogElement.showModal();
e.stopPropagation();
e.preventDefault();
return;
}
}
$effect(() => {
document.addEventListener('keydown', docKey, false);
return () => {
document.removeEventListener('keydown', docKey);
};
});
</script>
<dialog class="card max-w-[50vw]" bind:this={dialogElement}>
<form onsubmit={preventDefault(createApplication)}>
<fieldset>
<label class="flabel" for="title">Link</label>
<input class="finput" id="title" bind:value={link} required />
</fieldset>
</form>
</dialog>

View File

@ -0,0 +1,109 @@
<script lang="ts">
import {
ApplicationStatus,
ApplicationStatusMaping,
type Application
} from '$lib/ApplicationsStore.svelte';
import type { AsEnum } from '$lib/ApplicationsStore.svelte';
import { post } from '$lib/utils';
let {
application,
onreload
}: {
application?: Application;
onreload: (item: Application) => void;
} = $props();
let filter = $state('');
let applications: Application[] = $state([]);
let dialogElement: HTMLDialogElement;
async function getApplicationList() {
applications = await post('application/list', {});
}
$effect(() => {
getApplicationList();
});
function docKey(e: KeyboardEvent) {
if (e.ctrlKey && e.code === 'KeyK') {
dialogElement.showModal();
e.stopPropagation();
e.preventDefault();
return;
}
}
$effect(() => {
document.addEventListener('keydown', docKey, false);
return () => {
document.removeEventListener('keydown', docKey);
};
});
</script>
<dialog class="card max-w-[50vw]" bind:this={dialogElement}>
<div class="flex">
<input placeholder="Filter" class="p-2 flex-grow" bind:value={filter} />
<div>
{applications.length}
</div>
</div>
<div class="overflow-y-auto overflow-x-hidden flex-grow p-2">
{#each applications.filter((i) => {
if (application && i.id == application.id) {
return false;
}
if (!filter) {
return true;
}
if (filter.includes('@') && i.company) {
const f = new RegExp(filter.split('@')[0].trim(), 'ig');
const c = new RegExp(filter.split('@')[1].trim(), 'ig');
return i.title.match(f) && i.company.match(c);
}
const f = new RegExp(filter, 'ig');
let x = i.title;
if (i.company) {
x = `${x} @ ${i.company}`;
}
return x.match(f);
}) as item}
<div class="card p-2 my-2 bg-slate-100 max-w-full" role="none">
<button class="text-left max-w-full" type="button" onclick={() => {
dialogElement.close()
onreload(item)
}}>
<h2 class="text-lg text-blue-500 flex justify-between">
<div>
{item.title}
{#if item.company}
<div class="text-violet-800">
@ {item.company}
</div>
{/if}
</div>
<div>
{#if !([ApplicationStatus.ToApply, ApplicationStatus.WorkingOnIt] as AsEnum<ApplicationStatus>[]).includes(item!.status)}
{ApplicationStatusMaping[item.status]}
{/if}
</div>
</h2>
<span
class="text-violet-600 overflow-hidden whitespace-nowrap block max-w-full"
>
{item.url}
</span>
</button>
</div>
{/each}
</div>
</dialog>

View File

@ -3,7 +3,8 @@
ApplicationStatus, ApplicationStatus,
ApplicationStatusMaping, ApplicationStatusMaping,
applicationStore, applicationStore,
type Application type Application,
type AsEnum
} from '$lib/ApplicationsStore.svelte'; } from '$lib/ApplicationsStore.svelte';
import { put, preventDefault, post, get, deleteR } from '$lib/utils'; import { put, preventDefault, post, get, deleteR } from '$lib/utils';
@ -14,6 +15,8 @@
import DropZone from './DropZone.svelte'; import DropZone from './DropZone.svelte';
import { userStore } from '$lib/UserStore.svelte'; import { userStore } from '$lib/UserStore.svelte';
import LinkApplication from './LinkApplication.svelte'; import LinkApplication from './LinkApplication.svelte';
import SearchApplication from './SearchApplication.svelte';
import NewApplication from './NewApplication.svelte';
let activeItem: Application | undefined = $state(); let activeItem: Application | undefined = $state();
@ -24,6 +27,8 @@
let lastExtData: any = $state(undefined); let lastExtData: any = $state(undefined);
let autoExtData = false; let autoExtData = false;
let showExtraData = $state(false);
async function activate(item?: Application) { async function activate(item?: Application) {
if (!item) { if (!item) {
return; return;
@ -113,8 +118,6 @@
} }
} }
console.log('setting up interest');
window.addEventListener('message', onMessage); window.addEventListener('message', onMessage);
window.postMessage({ type: 'REGISTER_INTEREST' }); window.postMessage({ type: 'REGISTER_INTEREST' });
return () => { return () => {
@ -156,7 +159,7 @@
applicationStore.loadItem = undefined; applicationStore.loadItem = undefined;
}); });
async function moveStatus(status: number) { async function moveStatus(status: AsEnum<typeof ApplicationStatus>, moveOut = true) {
if (!activeItem) return; if (!activeItem) return;
// Deactivate active item // Deactivate active item
try { try {
@ -171,7 +174,11 @@
} }
applicationStore.loadApplications(true); applicationStore.loadApplications(true);
applicationStore.loadAplyed(true); applicationStore.loadAplyed(true);
activeItem = undefined; if (moveOut) {
activeItem = undefined;
} else {
activeItem.status = status;
}
//openedWindow?.close(); //openedWindow?.close();
//openedWindow = undefined; //openedWindow = undefined;
} }
@ -240,6 +247,20 @@
{statusMapping} {statusMapping}
</div> </div>
{/if} {/if}
{#if showExtraData}
<fieldset class="max-w-full min-w-0 overflow-hidden">
<div class="flabel">Id</div>
<div class="finput bg-white w-full break-keep">
{activeItem.id}
</div>
</fieldset>
<fieldset class="max-w-full min-w-0 overflow-hidden">
<div class="flabel">Create Time</div>
<div class="finput bg-white w-full break-keep">
{activeItem.create_time}
</div>
</fieldset>
{/if}
<div class="flex gap-2"> <div class="flex gap-2">
<fieldset class="grow"> <fieldset class="grow">
<label class="flabel" for="title">Company</label> <label class="flabel" for="title">Company</label>
@ -395,6 +416,13 @@
> >
👋 👋
</button> </button>
<button
class:btn-primary={!showExtraData}
class:btn-confirm={showExtraData}
onclick={() => (showExtraData = !showExtraData)}
>
🔬
</button>
</div> </div>
</div> </div>
{#if applicationStore.dragging} {#if applicationStore.dragging}
@ -423,13 +451,15 @@
> >
Ignore it Ignore it
</DropZone> </DropZone>
{/if}
{#if [ApplicationStatus.WorkingOnIt, ApplicationStatus.Expired].includes(activeItem.status)}
<!-- Expired --> <!-- Expired -->
<DropZone <DropZone
icon="clock-fill text-orange-500" icon="clock-fill text-orange-500"
ondrop={() => { ondrop={() => {
if (activeItem && activeItem.status === ApplicationStatus.Expired) { if (activeItem && activeItem.status === ApplicationStatus.Expired) {
moveStatus(ApplicationStatus.ToApply); moveStatus(ApplicationStatus.ToApply, false);
} else { } else {
moveStatus(ApplicationStatus.Expired); moveStatus(ApplicationStatus.Expired);
} }
@ -437,7 +467,9 @@
> >
Mark as expired Mark as expired
</DropZone> </DropZone>
{/if}
{#if activeItem.status === ApplicationStatus.WorkingOnIt}
<!-- Repeated --> <!-- Repeated -->
<DropZone icon="trash-fill text-danger" ondrop={() => remove()} <DropZone icon="trash-fill text-danger" ondrop={() => remove()}
>Delete it</DropZone >Delete it</DropZone
@ -522,3 +554,11 @@
onreload={(item) => (activeItem = item)} onreload={(item) => (activeItem = item)}
/> />
{/if} {/if}
<SearchApplication application={activeItem} onreload={(item) => (activeItem = item)} />
<NewApplication
onreload={(item) => {
activate(item);
}}
/>

View File

@ -3,6 +3,9 @@ import { defineConfig } from 'vite';
export default defineConfig({ export default defineConfig({
plugins: [sveltekit()], plugins: [sveltekit()],
server: {
host: true,
},
build: { build: {
commonjsOptions: { commonjsOptions: {
esmExternals: true esmExternals: true