Przejdź do głównej treści

Menedżer Freelance

Grafika SVG Sprint

Masz wielu klientów, kilka projektów jednocześnie, terminy do dopilnowania i płatności do kontrolowania? Menedżer Freelance to praktyczna aplikacja stworzona z myślą o freelancerach, którzy chcą mieć wszystko w jednym miejscu.

Co zyskujesz?

Jak działa aplikacja?

Aplikacja działa bez instalacji i bez skomplikowanej konfiguracji. Wystarczy ją uruchomić w przeglądarce i od razu możesz rozpocząć pracę.

1. Dodaj klientów

Wpisz nazwę klienta oraz dane kontaktowe, aby zbudować własną bazę współprac.

2. Twórz nowe zlecenia

Dodawaj projekty, przypisuj je do klientów, ustawiaj kwotę, status realizacji oraz termin zakończenia.

3. Monitoruj postępy

Sprawdzaj, które projekty są aktywne, zakończone lub wymagają uwagi.

4. Kontroluj finanse

Aplikacja automatycznie podlicza przychody, dzięki czemu zawsze wiesz, ile zarabiasz.

5. Wszystko zapisuje się automatycznie

Dane przechowywane są w pamięci przeglądarki (Local Storage), więc po zamknięciu strony nic nie przepada.

Dlaczego warto?

Freelancerzy często korzystają z kilku narzędzi jednocześnie: notatek, arkuszy Excel, kalendarza i wiadomości e-mail. Menedżer Freelance łączy najważniejsze funkcje w jednym miejscu i oszczędza Twój czas.

Dla kogo?

  • grafików
  • programistów
  • copywriterów
  • marketerów
  • fotografów
  • konsultantów
  • wszystkich pracujących na własny rachunek

Zacznij już dziś

Uporządkuj klientów, projekty i finanse. Skup się na pracy, a organizację zostaw aplikacji Menedżer Freelance.

Polityka Prywatności

Ochrona Twoich danych

Szanujemy Twoją prywatność i dbamy o bezpieczeństwo informacji wprowadzanych do aplikacji Menedżer Freelance.

Jak działają dane w aplikacji?

Aplikacja została zaprojektowana jako narzędzie działające lokalnie w przeglądarce internetowej. Oznacza to, że dane wpisywane przez użytkownika, takie jak:

  • lista klientów
  • nazwy projektów i zleceń
  • terminy realizacji
  • kwoty i przychody
  • ustawienia aplikacji

zapisywane są wyłącznie na urządzeniu użytkownika przy użyciu technologii Local Storage przeglądarki.

Brak przesyłania danych na serwer

Aplikacja nie wysyła wprowadzonych danych do zewnętrznych serwerów, baz danych ani usług trzecich. Wszystkie informacje pozostają lokalnie na Twoim komputerze lub urządzeniu.

Pełna kontrola użytkownika

Użytkownik ma pełną kontrolę nad swoimi danymi. Może je w dowolnym momencie:

  • edytować
  • usuwać
  • wyczyścić pamięć przeglądarki
  • usunąć aplikację z urządzenia

Bezpieczeństwo

Zalecamy korzystanie z aktualnej wersji przeglądarki internetowej oraz zabezpieczenie urządzenia hasłem, aby zwiększyć poziom ochrony danych lokalnych.

Pliki cookies

Podstawowa wersja aplikacji nie wykorzystuje plików cookies do śledzenia użytkowników ani celów marketingowych.

Zmiany polityki prywatności

W przypadku rozbudowy aplikacji o nowe funkcje online (np. logowanie, synchronizacja w chmurze, kopie zapasowe), polityka prywatności może zostać zaktualizowana.

Kontakt

W razie pytań dotyczących prywatności i bezpieczeństwa danych skontaktuj się z administratorem aplikacji.

Menedżer Freelance

Klienci, projekty, terminy i płatności

Klienci

0

Aktywne zlecenia

0

Przychód

0 zł

Dodaj klienta

Lista klientów

    Zlecenia

    Projekt Klient Status Kwota Termin Akcje

    Kod po stronie przeglądarki

    <link type="text/css" href="http://www.dariuszrorat.ugu.pl/assets/css/bootstrap/wcag-outline.min.css" rel="stylesheet">
    <div id="app" class="py-4">
        <div class="d-flex justify-content-between align-items-center mb-4">
            <div>
                <h3 class="h3 mb-0">Menedżer Freelance</h3>
                <small class="text-muted">Klienci, projekty, terminy i płatności</small>
            </div>
            <button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#jobModal">+ Nowe zlecenie</button>
        </div>
        <div class="row g-3 mb-4">
            <div class="col-md-4">
                <div class="card p-3">
                    <h4 class="h6">Klienci</h4>
                    <div id="clientsCount" class="display-6">0</div>
                </div>
            </div>
            <div class="col-md-4">
                <div class="card p-3">
                    <h4 class="h6">Aktywne zlecenia</h4>
                    <div id="activeCount" class="display-6">0</div>
                </div>
            </div>
            <div class="col-md-4">
                <div class="card p-3">
                    <h4 class="h6">Przychód</h4>
                    <div id="income" class="display-6">0 zł</div>
                </div>
            </div>
        </div>
        <div class="row g-4">
            <div class="col-lg-4">
                <div class="card p-3">
                    <h4 class="h5">Dodaj klienta</h4>
                    <input id="clientName" class="form-control mb-2" placeholder="Nazwa klienta" aria-label="Nazwa klienta">
                    <input id="clientEmail" class="form-control mb-2" placeholder="Email" aria-label="Email">
                    <button class="btn btn-success w-100" onclick="addClient()">Dodaj</button>
                </div>
                <div class="card p-3 mt-3">
                    <h4 class="h5">Lista klientów</h4>
                    <ul id="clientsList" class="list-group list-group-flush"></ul>
                </div>
            </div>
            <div class="col-lg-8">
                <div class="card p-3">
                    <div class="d-flex justify-content-between align-items-center mb-3">
                        <h4 class="h5 mb-0">Zlecenia</h4>
                        <input id="search" class="form-control w-auto" placeholder="Szukaj..." aria-label="Szukaj" oninput="renderJobs()">
                    </div>
                    <div class="table-responsive">
                        <table class="table align-middle">
                            <thead>
                                <tr>
                                    <th>Projekt</th>
                                    <th>Klient</th>
                                    <th>Status</th>
                                    <th>Kwota</th>
                                    <th>Termin</th>
                                    <th>Akcje</th>
                                </tr>
                            </thead>
                            <tbody id="jobsTable"></tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="modal fade" id="jobModal" tabindex="-1">
        <div class="modal-dialog">
            <div class="modal-content">
                <div class="modal-header">
                    <h4 class="h5 modal-title">Nowe zlecenie</h4>
                    <button class="btn-close" data-bs-dismiss="modal" aria-label="Zamknij"></button>
                </div>
                <div class="modal-body">
                    <input id="jobTitle" class="form-control mb-2" placeholder="Nazwa projektu" aria-label="Nazwa projektu">
                    <select id="jobClient" class="form-select mb-2" aria-label="Klient"></select>
                    <select id="jobStatus" class="form-select mb-2" aria-label="Status">
                        <option>Nowe</option>
                        <option>W trakcie</option>
                        <option>Zakończone</option>
                    </select>
                    <input id="jobAmount" type="number" class="form-control mb-2" placeholder="Kwota" aria-label="Kwota">
                    <input id="jobDeadline" type="date" class="form-control mb-2" aria-label="Deadline">
                </div>
                <div class="modal-footer"><button class="btn btn-primary" onclick="addJob()">Zapisz</button></div>
            </div>
        </div>
    </div>
    <script>
        let clients = JSON.parse(localStorage.getItem('fm_clients') || '[]');
        let jobs = JSON.parse(localStorage.getItem('fm_jobs') || '[]');
        function save() {
            localStorage.setItem('fm_clients', JSON.stringify(clients));
            localStorage.setItem('fm_jobs', JSON.stringify(jobs));
        }
        function addClient() {
            const name = document.getElementById('clientName').value.trim();
            const email = document.getElementById('clientEmail').value.trim();
            if (!name) return;
            clients.push({
                id: Date.now(),
                name,
                email
            });
            document.getElementById('clientName').value = '';
            document.getElementById('clientEmail').value = '';
            refresh();
        }
        function addJob() {
            const title = jobTitle.value.trim();
            if (!title) return;
            jobs.push({
                id: Date.now(),
                title,
                clientId: +jobClient.value,
                status: jobStatus.value,
                amount: +jobAmount.value || 0,
                deadline: jobDeadline.value
            });
            bootstrap.Modal.getInstance(document.getElementById('jobModal')).hide();
            jobTitle.value = '';
            jobAmount.value = '';
            jobDeadline.value = '';
            refresh();
        }
        function deleteJob(id) {
            jobs = jobs.filter(j => j.id !== id);
            refresh();
        }
        function renderClients() {
            clientsList.innerHTML = '';
            jobClient.innerHTML = '';
            clients.forEach(c => {
                clientsList.innerHTML += `<li class="list-group-item d-flex justify-content-between"><span>${c.name}</span><small>${c.email||''}</small></li>`;
                jobClient.innerHTML += `<option value="${c.id}">${c.name}</option>`;
            });
        }
        function badge(status) {
            return status === 'Zakończone' ? 'success' : status === 'W trakcie' ? 'warning text-dark' : 'secondary';
        }
        function renderJobs() {
            const q = search.value.toLowerCase();
            jobsTable.innerHTML = '';
            jobs.filter(j => j.title.toLowerCase().includes(q)).forEach(j => {
                const c = clients.find(x => x.id === j.clientId) || {
                    name: '-'
                };
                jobsTable.innerHTML += `<tr><td>${j.title}</td><td>${c.name}</td><td><span class="badge bg-${badge(j.status)}">${j.status}</span></td><td>${j.amount} zł</td><td>${j.deadline||'-'}</td><td><button class="btn btn-sm btn-outline-danger" onclick="deleteJob(${j.id})">Usuń</button></td></tr>`;
            });
        }
        function stats() {
            clientsCount.textContent = clients.length;
            activeCount.textContent = jobs.filter(j => j.status !== 'Zakończone').length;
            income.textContent = jobs.reduce((a, b) => a + b.amount, 0) + ' zł';
        }
        function refresh() {
            save();
            renderClients();
            renderJobs();
            stats();
        }
        refresh();
    </script>

    Kod po stronie serwera

    Brak kodu serwera

    Ta aplikacja działa wyłącznie w przeglądarce i nie korzysta z kodu po stronie serwera.

    Licencja

    ## BSD-3-Clause License Agreement
    BSD-3-Clause
    Сopyright (c) 2026 Dariusz Rorat
    
    All rights reserved.
    
    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:
    
    1. Redistributions of source code must retain the above copyright notice,
       this list of conditions and the following disclaimer.
    
    2. Redistributions in binary form must reproduce the above copyright notice,
       this list of conditions and the following disclaimer in the documentation
       and/or other materials provided with the distribution.
    
    3. Neither the name of the copyright holder nor the names of its
       contributors may be used to endorse or promote products derived from
       this software without specific prior written permission.
    
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    29 kwietnia 2026 2

    Kategorie

    Technologie

    Dziękujemy!
    ()

    Masz pomysł na podobną aplikację?

    Chętnie pomogę zaplanować MVP, funkcjonalności oraz dalszy rozwój produktu.

    Omówmy Twój pomysł

    Informacja o cookies

    Moja strona internetowa wykorzystuje wyłącznie niezbędne pliki cookies, które są wymagane do jej prawidłowego działania. Nie używam ciasteczek w celach marketingowych ani analitycznych. Korzystając z mojej strony, wyrażasz zgodę na stosowanie tych plików. Możesz dowiedzieć się więcej w mojej polityce prywatności.