diff --git a/shared/src/ethlance/shared/constants.cljs b/shared/src/ethlance/shared/constants.cljs index a3443d35..f791352c 100644 --- a/shared/src/ethlance/shared/constants.cljs +++ b/shared/src/ethlance/shared/constants.cljs @@ -391,49 +391,82 @@ (def skills ["A/B testing" + "API development" "API integration" + "AR/VR development" + "AWS" "Accounting" "Ad campaign management" "Adaptability" + "AdonisJS" "Agile methodology" "Agile project management" + "Airtable" + "Alpine.js" "Analytical skills" "Analytics knowledge" "Analytics reporting" + "Angular" + "Ansible" + "Apache Kafka" + "Apache Spark" "App store optimization" + "Artificial intelligence" + "Assembly" + "Astro" "Attention to deadlines" "Attention to detail" + "Augmented reality" + "Aurelia" "Automate tasks" + "Azure" "B2B sales" + "Backbone.js" + "Bash scripting" + "Blazor" + "Blockchain development" "Blogging" + "Bootstrap" "Brand development" "Brand monitoring" "Brand strategy" "Branding design" "Budget management" + "Bulma CSS" + "Bun runtime" + "C" + "C#" "C++" + "CI/CD pipelines" + "COBOL" "CRM integration" "CRM management" "CSS" - "ChatGPT and similar" + "Chakra UI" + "ChatGPT integration" + "Claude API integration" "Client communication" "Client management" "Client retention" "Client satisfaction" "Clojure / ClojureScript" "Cloud computing" + "CockroachDB" "Code debugging" + "CodeIgniter" "Coding proficiency" "Coding" + "CoffeeScript" "Cognitive computing strategies" "Collaboration skills" "Communication planning" "Communication" "Competitive analysis" "Computer programming knowledge" - "Computer vision techniques" + "Computer vision" "Conceptual thinking" "Conflict resolution" + "Container orchestration" "Content curation" "Content management" "Content strategy" @@ -447,45 +480,99 @@ "Creative writing" "Crisis management" "Critical thinking" + "Crystal" + "Cryptocurrency trading" + "Cucumber" "Customer engagement" "Customer feedback" "Customer retention" "Customer service" "Cybersecurity" - "Data analysis" - "Data analysis" + "Cypress" + "D" + "DApp development" + "Dart" "Data analysis" "Data cleaning" "Data entry accuracy" "Data management" "Data migration" - "Data visualization" + "Data science" "Data visualization" "Database design" "Database management" "Database programming" - "Deep learning model" + "DeFi protocols" + "Deep learning" + "Delphi" + "Deno" + "DevOps" "Digital advertising" "Digital asset management" "Digital content creation" "Digital marketing" "Digital prototyping" "Digital strategy" + "Discord bot development" + "Django" + "Docker" + "Drupal" "E-commerce management" + "ETL processes" + "Edge computing" + "Electron apps" + "Elixir" + "Elm" "Email automation" "Email campaigns" "Email management" "Email marketing" "Email security" + "Ember.js" + "Erlang" + "Ethereum development" "Event planning" "Excel proficiency" "Experience with CRM" + "Express.js" + "F#" + "FastAPI" + "Fastify" + "Figma design" "File management skills" "Financial analysis" "Financial reporting" + "Flask" + "Flutter" "Fluency in multiple languages" + "Fortran" + "Foundation CSS" + "Framer development" + "GCP (Google Cloud)" + "GPT fine-tuning" + "GPT prompt engineering" + "Game development" + "Gatsby.js" + "Gemini API" + "Gin framework" + "Git version control" + "GitHub Actions" + "Go (Golang)" + "Gradle" + "Grails" + "GraphQL" "Graphic design" + "Groovy" + "Gulp.js" "HTML" + "Hack" + "Hadoop" + "Hapi.js" + "Haskell" + "Headless CMS" + "Hibernate" + "Hugo" + "Hyperledger" "IT architecture" "IT compliance knowledge" "IT hardware troubleshooting" @@ -498,33 +585,87 @@ "IT software proficiency" "IT support skills" "IT troubleshooting" + "Idris" "Image editing" + "Image generation AI" "Influencer marketing" "Influencer outreach" "Internet research abilities" "Inventory management" + "Ionic" + "JAMstack development" + "JQuery" + "Julia" + "Jasmine" "Java" "JavaScript" + "Jekyll" + "Jenkins" + "Jest" + "Joomla" + "Jupyter notebooks" + "Keras" + "Koa.js" + "Kotlin" + "Kubernetes" + "LLM integration" + "LaTeX" + "LangChain" + "Laravel" "Lead generation" "Leadership qualities" - "Machine learning algorithms" + "Less CSS" + "Linux administration" + "Lisp" + "Lit" + "Lua" + "Low-code platforms" + "MATLAB" + "MUI (Material-UI)" + "Machine learning" + "Mantine" "Market positioning" "Market research" "Market segmentation" "Market trends" "Marketing automation" + "Material Design" + "Maven" "Mental arithmetic" + "Metaverse development" + "Meteor.js" + "Micronaut" + "Microservices" "Microsoft Office proficiency" + "Midjourney prompting" "Mobile app development" "Mobile marketing" "Mobile optimization" + "Mocha" + "MongoDB" "Multi-channel marketing" "Multitasking ability" + "MySQL" + "NFT creation" + "NFT marketplace development" "Natural language processing" "Negotiation" + "Neo4j" + "Nest.js" "Network protocols" "Networking" "Neural network design" + "Next.js" + "Nginx" + "Nim" + "No-code development" + "Node.js" + "Notion management" + "NumPy" + "Nuxt.js" + "OAuth implementation" + "Objective-C" + "Ocaml" "Online community management" "Online fundraising" "Online reputation management" @@ -532,25 +673,61 @@ "Online sales" "Online scheduling" "Online training" + "OpenAI API" + "OpenGL" "Organizational skills" + "PHP" + "Pandas" + "Parcel" + "Pascal" "Performance evaluation" "Performance tracking" + "Perl" + "Phoenix framework" "Photo editing" - "Predictive analytics techniques" + "Playwright" + "Polymer" + "PostgreSQL" + "PowerShell" + "Preact" + "Predictive analytics" "Present complex information" "Presentation design" + "Prisma ORM" "Problem solving" + "Processing" "Product launches" "Product management" "Product photography" "Productivity tools" "Programming" + "Progressive web apps" "Project coordination" "Project management" - "Project management" + "Prolog" + "Prompt engineering" + "Protractor" "Public speaking" + "Pug" + "Puppet" + "PyTorch" + "Python" + "Qiskit" + "Qt framework" + "Quarkus" "Quality assurance" - "Reinforcement learning algorithms" + "R" + "RAG systems" + "REST API design" + "RSpec" + "Racket" + "React Native" + "React.js" + "ReasonML" + "Redis" + "Redux" + "Reinforcement learning" + "Remix framework" "Remote communication" "Remote team management" "Remote training" @@ -558,42 +735,94 @@ "Report writing" "Research" "Responsive design" + "Rollup" + "Ruby" + "Ruby on Rails" + "Rust" "SEO auditing" "SEO optimization" "SEO strategy" "SQL" + "SQLAlchemy" + "SQLite" + "Sails.js" "Sales" + "Sanity CMS" + "Sass/SCSS" + "Scala" + "Scheme" + "Scikit-learn" "Security protocols" + "Selenium" + "Semantic UI" "Server management" + "Serverless architecture" + "Shopify development" + "Sinatra" + "Smalltalk" + "Smart contract auditing" + "Smart contract development" "Social media advertising" "Social media analytics" "Social media engagement" "Social media management" "Software integration" "Software licensing" - "Speech recognition technology" + "Solana development" + "Solid.js" + "Solidity" + "Speech recognition" "Spreadsheets" - "Stable diffusion" + "Spring Boot" + "Spring Framework" + "Stable Diffusion" + "Stimulus" + "Storybook" "Strategy development" + "Strapi" + "Stripe integration" "Strong typing skills" + "Stylus CSS" + "Supabase" "Supplier relations" "Supply chain management" + "Svelte/SvelteKit" + "Swift" + "Symfony" "System architecture" "Systems analysis" + "Tailwind CSS" + "Tcl" "Team building" "Team collaboration" "Team leadership" "Teamwork" "Technical proficiency" + "Technical writing" + "Telegram bot development" + "TensorFlow" + "Terraform" + "Three.js" "Time management" "Time tracking" + "Token economics" "Trend analysis" "Troubleshoot hardware issues" + "Turbo" + "TypeORM" + "TypeScript" "UI/UX design" "UX design" + "Unity development" + "Unreal Engine" "User retention" "User testing" + "V" + "VHDL" + "Vala" + "Vector databases" "Vendor management" + "Verilog" "Video conferencing" "Video editing" "Video marketing" @@ -603,17 +832,41 @@ "Virtual event planning" "Virtual team management" "Virtualization" + "Visual Basic" + "Vite" + "Voice AI integration" + "Vue.js" + "Vuetify" + "WASM development" + "Web Components" + "Web3 development" "Web accessibility" "Web analytics" "Web content management" "Web design" "Web development" + "Web scraping" + "WebAssembly" + "WebGL" + "WebRTC" + "Webflow development" + "Webpack" "Website migration" "Website optimization" "Website security" "WordPress" "Work independently" - "Work under pressure"]) + "Work under pressure" + "Xamarin" + "Yii framework" + "Zapier automation" + "Zend Framework" + "Zero-knowledge proofs" + "Zig" + "Zustand" + "iOS development" + "jQuery Mobile" + "tRPC"]) (def categories diff --git a/shared/src/ethlance/shared/spec.cljs b/shared/src/ethlance/shared/spec.cljs index 7726315f..05333042 100644 --- a/shared/src/ethlance/shared/spec.cljs +++ b/shared/src/ethlance/shared/spec.cljs @@ -4,6 +4,7 @@ [cljs.spec.alpha :as s] [cljs.pprint] [clojure.set :as set] + [clojure.string :as str] [district.validation :refer [length? email? not-neg?]] [ethlance.shared.constants :as constants] [medley.core :refer [map-kv-vals]])) @@ -73,9 +74,15 @@ (s/def :job/title (s/and string? (comp not empty?))) (s/def :job/required-skills (comp not empty?)) +(s/def ::token-amount not-neg?) +(s/def ::human-amount (s/and string? #(not (clojure.string/blank? %)))) +(s/def ::decimals not-neg?) + +(s/def :job/token-amount + (s/keys :req-un [::token-amount ::human-amount ::decimals])) (s/def :page.new-job/create - (s/keys :req [:job/title :job/required-skills])) + (s/keys :req [:job/title :job/required-skills :job/token-amount])) (s/def :page.sign-up/update-candidate diff --git a/ui/resources/public/less/page/profile.less b/ui/resources/public/less/page/profile.less index 33188366..1d128847 100644 --- a/ui/resources/public/less/page/profile.less +++ b/ui/resources/public/less/page/profile.less @@ -43,12 +43,13 @@ } > .title { + width: 100%; grid-area: title; display: grid; grid-template-areas: - 'profile-image name' - 'profile-image detail'; - grid-template-columns: 72px auto; + 'profile-image name edit-button' + 'profile-image detail edit-button'; + grid-template-columns: 72px auto max-content; grid-template-rows: auto auto; @media #media[tablet-query] { @@ -74,6 +75,13 @@ padding: 0.5em 1.4em; } + + > .edit-button { + grid-area: edit-button; + align-self: start; + justify-self: end; + padding-top: 0.5em; + } } > .biography { diff --git a/ui/resources/public/less/page/sign-up.less b/ui/resources/public/less/page/sign-up.less index 96266db5..d2305a11 100644 --- a/ui/resources/public/less/page/sign-up.less +++ b/ui/resources/public/less/page/sign-up.less @@ -114,7 +114,14 @@ > .dropzone { width: 100%; + height: 100%; position: relative; + cursor: pointer; + + > img { + width: 100%; + height: 100%; + } .file-input-label { display: flex; diff --git a/ui/src/ethlance/ui/component/file_drag_input.cljs b/ui/src/ethlance/ui/component/file_drag_input.cljs index 5ddd9ef1..dbacabc1 100644 --- a/ui/src/ethlance/ui/component/file_drag_input.cljs +++ b/ui/src/ethlance/ui/component/file_drag_input.cljs @@ -40,25 +40,26 @@ (.readAsArrayBuffer ab-reader f)) (when on-file-rejected (on-file-rejected fprops))))))] - (fn [{:keys [form-data id] + (fn [{:keys [form-data id current-src] :as opts}] - (let [{:keys [url-data]} (get-in @form-data [id :selected-file])] - [:div.dropzone - {:on-drag-over allow-drop + (let [{:keys [url-data]} (get-in @form-data [id :selected-file]) + file-input-id (id-for-path id)] + [:label.dropzone + {:htmlFor file-input-id + :on-drag-over allow-drop :on-drop #(do (.preventDefault %) (handle-files-select (.. % -dataTransfer -files))) :on-drag-enter allow-drop} - [:img {:src (or url-data empty-img-src)}] + [:img {:src (or url-data current-src empty-img-src)}] - (when (not url-data) - [:label.file-input-label - {:for (id-for-path id)} + (when (not (or url-data current-src)) + [:div.file-input-label [c-icon {:name :ic-upload :color :dark-blue :inline? false}] [:div (get opts :label "File...")]]) [:input {:type :file - :id (id-for-path id) + :id file-input-id :on-change (fn [e] (handle-files-select (-> e .-target .-files)))}]])))) diff --git a/ui/src/ethlance/ui/page/new_job/events.cljs b/ui/src/ethlance/ui/page/new_job/events.cljs index cf9125cb..98f233fa 100644 --- a/ui/src/ethlance/ui/page/new_job/events.cljs +++ b/ui/src/ethlance/ui/page/new_job/events.cljs @@ -28,20 +28,21 @@ (def interceptors [re/trim-v]) +(def default-token-amount + {:token-amount 0 :human-amount "0" :decimals 18}) (def state-default - {:job/title "Rauamaak on meie saak" - :job/description "Tee t88d ja n2e vaeva" - :job/category "Admin Support" + {:job/title "" + :job/description "" + :job/category "" :job/bid-option :hourly-rate :job/required-experience-level :intermediate :job/estimated-project-length :day :job/required-availability :full-time - :job/required-skills (set (repeatedly 2 #(rand-nth constants/skills))) + :job/required-skills #{} :job/token-type :eth - :job/token-amount 0.69 - :job/token-address "0x1111111111111111111111111111111111111111" - :job/token-id 0 + :job/token-address "" + :job/token-amount default-token-amount :job/with-arbiter? false :job/invited-arbiters #{} :job/token-decimals 18}) @@ -119,7 +120,7 @@ (fn [] [:dispatch [:page.new-job/decimals-response default-decimals]]))] {:fx [(decimals-fx-fn)] :db (-> db - (assoc-in ,,, [state-key :job/token-amount] 1) + (assoc-in ,,, [state-key :job/token-amount] default-token-amount) (assoc-in ,,, [state-key :job/token-type] token-type))}))) @@ -215,11 +216,12 @@ ::send-create-job-tx (fn [{:keys [db]} _] (let [employer (get-job-creation-param db :employer) - offered-value (get-job-creation-param db :offered-value) + token-type (get-job-creation-param db :token-type) + offered-value (cond-> (get-job-creation-param db :offered-value) + (#{:eth :erc20} token-type) (assoc-in [:token :tokenId] 0)) ipfs-hash (get-job-creation-param db :ipfs-hash) arbiters (get-job-creation-param db :arbiters) tx-opts-base {:from employer} - token-type (get-job-creation-param db :token-type) tx-opts (if (= token-type :eth) (assoc tx-opts-base :value (:value offered-value)) tx-opts-base)] diff --git a/ui/src/ethlance/ui/page/profile.cljs b/ui/src/ethlance/ui/page/profile.cljs index 3b1b84ae..5613c407 100644 --- a/ui/src/ethlance/ui/page/profile.cljs +++ b/ui/src/ethlance/ui/page/profile.cljs @@ -291,6 +291,10 @@ [:div.profile-image [c-profile-image {:src image-url}]] [:div.name name] + [:div.edit-button + [c-button (merge {:size :small} (navigation/link-params {:route :route.me/sign-up + :query {:tab :candidate}})) + [c-button-label "Edit Profile"]]] [:div.detail professional-title]] [:div.biography biography] [c-rating-box rating] @@ -343,6 +347,10 @@ [:div.profile-image [c-profile-image {:src image-url}]] [:div.name name] + [:div.edit-button + [c-button (merge {:size :small} (navigation/link-params {:route :route.me/sign-up + :query {:tab :employer}})) + [c-button-label "Edit Profile"]]] [:div.detail professional-title]] [:div.biography biography] [c-rating-box rating] @@ -456,6 +464,10 @@ [:div.profile-image [c-profile-image {:src image-url}]] [:div.name name] + [:div.edit-button + [c-button (merge {:size :small} (navigation/link-params {:route :route.me/sign-up + :query {:tab :arbiter}})) + [c-button-label "Edit Profile"]]] [:div.detail professional-title]] [:div.biography biography] [c-rating-box rating] diff --git a/ui/src/ethlance/ui/page/sign_up.cljs b/ui/src/ethlance/ui/page/sign_up.cljs index f5b35340..80d93130 100644 --- a/ui/src/ethlance/ui/page/sign_up.cljs +++ b/ui/src/ethlance/ui/page/sign_up.cljs @@ -9,7 +9,6 @@ [district.ui.router.subs :as router.subs] [ethlance.shared.constants :as constants] [ethlance.shared.spec :refer [validate-keys]] - [ethlance.ui.component.button :refer [c-button c-button-icon-label]] [ethlance.ui.component.currency-input :refer [c-currency-input]] [ethlance.ui.component.email-input :refer [c-email-input]] [ethlance.ui.component.file-drag-input :refer [c-file-drag-input]] @@ -24,7 +23,7 @@ [ethlance.ui.page.sign-up.events :as sign-up.events] [ethlance.ui.page.sign-up.subscriptions] [ethlance.ui.util.component :refer [>evt]] - [ethlance.ui.util.navigation :as navigation-utils] + [ethlance.ui.util.urls :as util.urls] [re-frame.core :as re] [reagent.core :as r] [taoensso.timbre :as log])) @@ -33,11 +32,12 @@ (defn- c-upload-image [] (let [form-data (r/atom {})] - (fn [] + (fn [{:keys [:form-values]}] [:div.upload-image [c-file-drag-input {:form-data form-data :id :file-info + :current-src (-> form-values :user/profile-image util.urls/ipfs-hash->gateway-url) :label "Upload file" :file-accept-pred (fn [{:keys [name type size]}] (log/debug "Veryfing acceptance of file" {:name name :type type :size size}) @@ -132,7 +132,7 @@ [:div.label "Sign Up"] [:div.first-forms [:div.form-image - [c-upload-image]] + [c-upload-image {:form-values form-values}]] [c-user-name-input {:form-values form-values :form-validation form-validation}] @@ -200,7 +200,7 @@ [:div.label "Sign Up"] [:div.first-forms [:div.form-image - [c-upload-image]] + [c-upload-image {:form-values form-values}]] [c-user-name-input {:form-values form-values :form-validation form-validation}] @@ -242,7 +242,7 @@ [:div.label "Sign Up"] [:div.first-forms [:div.form-image - [c-upload-image]] + [c-upload-image {:form-values form-values}]] [c-user-name-input {:form-values form-values :form-validation form-validation}]